Assigning nested struct members in Ruby FFI

Consider the following two FFI structures:

class A < FFI::Struct
layout :data, :int
end 

class B < FFI::Struct
layout :nested, A
end

      

To instantiate them:

a = A.new
b = B.new

      

Now when I try to assign a

to b.nested

like this:

b[:nested] = a

      

I am getting the following error:

ArgumentError: put not supported for FFI::StructByValue

      

FFI doesn't seem to allow assignment with the [] syntax if the nested structure is "nested by value", that is, it is not a pointer. If so, how do I then assign a

to b.nested

?

+3


source to share


1 answer


When you use FFI for a socket, it can work like this:

b = B.new
b[:nested][:data] = 42
b[:nested][:data] #=> 42

      

FFI object "b" created its own "a" object; you don't need to create your own.

It looks like you are trying to create your own "a" object and then store it:



a = A.new
b = B.new
b[:nested] = a  #=> fails because "a" is a Ruby object, not a nested value

      

The solution is to store "a" as a pointer:

require 'ffi'

class A < FFI::Struct
  layout :data, :int
end

class B < FFI::Struct
  layout :nested, :pointer  # we use a pointer, not a class
end

a = A.new
b = B.new

# Set some arbitrary data
a[:data] = 42

# Set :nested to the pointer to the "a" object
b[:nested] = a.pointer

# To prove it works, create a new object with the pointer
c = A.new(b[:nested])

# And prove we can get the arbitrary data    
puts c[:data]  #=> 42

      

+3


source







All Articles