ok, I finally resolved this using tuples in the following way:

type
  MyData = tuple[x, y, z: int, s: cstring]

proc new_list(data: ptr MyData): ptr MyData {.cdecl, exportc} =
  var data = cast[ptr MyData](alloc0(sizeof(MyData)))
  data.x = 111
  data.y = 222
  data.z = 333
  data.s = "nim rules!"
  
  return data

proc destroy_list(data: ptr MyData): void {.cdecl, exportc} =
  dealloc(data)

On the Ruby side I'm using the FFI to map the tuple to a struct-like object, making sure I get the byte offsets right (receiving pointer has offset 0)

class MyObject < FFI::Struct
    layout :data1, :int, 0,
      :data2, :int, 8,
      :data3, :int, 16,
      :name, :pointer, 24

I can now use Nim-generated data from Ruby, making sure I release the structure's memory when I'm done

my_data = NimDemo::MyObject.new(NimDemo.new_list)
puts my_data[:data1]
puts my_data[:data2]
puts my_data[:data3]
puts my_data[:name].read_string
# finished with it, so release it
NimDemo.destroy_list(my_data)

That means I can now pass a list of numeric values and strings (or combinations thereof) from Nim to Ruby. Which is pretty tidy

Many thanks to @mashingan and @Stefan_Salewski for steering me in the right direction!

2017-07-13 00:03:04

Great!

If you have some time to spare, it would be nice if you document or write your process to blog, it would be helpful for everyone

2017-07-13 02:42:48

I have now written a blog post about this

Feel free to ignore the first, introductory, part

2017-07-16 16:29:29
<<<••12••>>>