How to Specify a Struct as the Return Value of a Function in Rubyffi

How do I specify a struct as the return value of a function in RubyFFI?

class SOME_STRUCT < FFI::Struct 
layout :a, :float,
:b, :float
end

and then

attach_function 'fn_name', [], SOME_STRUCT

and if it stack-allocated struct:

typedef struct
{
float a, b;
} SOME_STRUCT;

you should use this:

attach_function 'fn_name', [], SOME_STRUCT.by_value

How to wrap function in Ruby FFI method that takes struct as argument?

Check how to use Structs in https://github.com/ffi/ffi/wiki/Structs, for your case:

class What < FFI::Struct
layout :d, :int,
:something, :pointer
end

Now attach the function, the argument, since you are passing the struct by value, is going to be What.by_value(replacing What by whatever you have named you struct class above):

attach_function 'doit', [What.by_value],:int

And now how to call the function:

mywhat = DoitLib::What.new
mywhat[:d] = 1234
DoitLib.doit(mywhat)

And now the complete file:

require 'ffi'

module DoitLib
extend FFI::Library
ffi_lib "path/to/yourlibrary.so"

class What < FFI::Struct
layout :d, :int,
:something, :pointer
end

attach_function 'doit', [What.by_value],:int

end

mywhat = DoitLib::What.new
mywhat[:d] = 1234
DoitLib.doit(mywhat)

Ruby ffi struct with value depending from other struct's size

Most likely a() is a C function that returns a struct which has a u8 property. That u8 property is probably a type, and if you are lucky it might be something fixed - it looks a lot like a char * buffer, from the name, and because u8 probably means "unsigned 8-bit integer" or :uchar

So a 261-byte :uchar array may be suitable (sorry don't know ffi for that)* - depends if MipHeader.size varies on different systems or in config.

I think what you want is

class MipInterface < FFI::Struct
layout(
:state, :uchar,
:port_handle, :pointer,
:input_buffer, RingBuffer,
:input_buffer_bytes, [:uint8, MipHeader.size+255+2]
)
end

I'm also guessing a(i).foo is some C convenience wrapper for "declare me an array length i of type 'foo'".

Is it possible to use Fiddle to pass or return a struct to native code?

I've gone through Fiddle documentation and as I can see it is not possible since even in core function definition Fiddle::Function.new it requires args that Fiddle::CParser can handle. I've done various test and to make it work I had to transform your code into something like this:

test2.c

#include <stdio.h>
#include <stdlib.h>

typedef struct {
char *data;
char *more_data;
size_t len;
} my_thing_t;

my_thing_t *returns_a_struct(void){
my_thing_t *structure = malloc(sizeof(my_thing_t));
structure->data = "test2";
structure->more_data = "I am more data";
structure->len = 5;
return structure;
};

irb

require 'fiddle'
require 'fiddle/import'
module Testmd
extend Fiddle::Importer
dlload './test2.dll'
RetStruct = struct ['char *data','char *more_data','size_t len']
extern 'RetStruct* returns_a_struct(void)'
end
include Testmd
2.2.1 :013 > res = Testmd::returns_a_struct(nil)
=> #<Fiddle::Pointer:0x00000000b12a10 ptr=0x00000000e066b0 size=0 free=0x00000000000000>
2.2.1 :014 > s = RetStruct.new(res)
=> #<Testmd::RetStruct:0x00000000c3e9e8 @entity=#<Fiddle::CStructEntity:0x000000007f0ad0 ptr=0x00000000e066b0 size=24 free=0x00000000000000>>
2.2.1 :015 > s.data.to_s
=> "test2"
2.2.1 :016 > s.more_data.to_s
=> "I am more data"
2.2.1 :017 > s.len
=> 5

What I came to is that Fiddle can operate with simple types but needs struct and union types to be passed using references. Still it has wrappers for this classes. Also these wrappers are inherited from Fiddle::Pointer what kinda leads us to conclusion they want us to use pointers for these data types.

If you want more details regarding this or you want to add this functionality you can go through their git repo.

Ruby Noobie: How to set a string value in an FFI Struct

FFI automatically rejects setting strings. Try changing it from :string to :char_array, as mentioned on this page:

:char_array - used ONLY in a struct layout where struct has a C-style string (char []) as a member

If that doesn't work, you're going to have to use a :pointer and convert it back into a string. It's not well documented, but MemoryPointer has a bunch of available functions, such as write_string, that should help.

If an ffi function modifies a pointer, should the owning struct be referenced mutable?

Contrary to popular belief, there is absolutely no borrowchecker-induced restriction in Rust on passing *const/*mut pointers. There doesn't need to be, because dereferencing pointers is inherently unsafe, and can only be done in such blocks, with the programmer verifying all necessary invariants manually. In your case, you need to tell the compiler that is a mutable reference, as you already suspected.

The interested reader should definitely give the ffi section of the nomicon a read, to find out about some interesting ways to shoot yourself in the foot with it.



Related Topics



Leave a reply



Submit