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!

Reply via email to