How to Use Fiddle to Pass or Return a Struct to Native Code

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.

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 can I pass a struct to a function as parameter?

You're looking for;

func test(class MyClass) {
fmt.Println(class.Name)
}

As it stands the method recognizes class as some object which implements the empty interface (meaning in that scope it's fields and methods are completely unknown) which is why you get the error.

Your other option is something like this;

func test(class interface{}) {
if c, ok := class.(MyClass); ok { // type assert on it
fmt.Println(c.Name)
}
}

But there is no reason to in your example. It only makes sense if you're going to do a type switch or have multiple code paths that do different things based on the actual type of class.

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)

Return Ruby's Fiddle::Pointer from C function

The solution for this is actually rather simple, though admittedly not as elegant or clean of a solution I was hoping to discover.

There are possibly more elaborate ways to go about this by including the headers for Fiddle, and building against it, but this was not really a viable solution, as I didn't want to restrict my C extension to only work with Ruby 2.0+, and would be perfectly acceptable to simply omit the method in the event Ruby version was less than 2.0.

First I include version.h, which gives access defines the macro RUBY_API_VERSION_MAJOR, which is all I really need to know in regards to whether or not Fiddle will be present or not.

This will be an abbreviated version to simply show how to get the Fiddle::Pointer class as a VALUE, and to create an instance.

#if RUBY_API_VERSION_MAJOR >= 2

rb_require("fiddle");
VALUE fiddle = rb_const_get(rb_cObject, rb_intern("Fiddle"));
rb_cFiddlePointer = rb_const_get(fiddle, rb_intern("Pointer"));

#endif

In this example, the class is stored in rb_cFiddlePointer, which can then be used to create and return a Fiddle::Pointer object from C.

    // Get basic data about the struct
struct RData *rdata = RDATA(self);
VALUE *args = xmalloc(sizeof(VALUE) * 2);
// Set the platform pointer-size address (could just use size_t here...)
#if SIZEOF_INTPTR_T == 4
args[0] = LONG2NUM((long) rdata->data);
#elif SIZEOF_INTPTR_T == 8
args[0] = LL2NUM((long long) rdata->data);
#else
args[0] = INT2NUM(0);
#endif
// Get size of structure
args[1] = INT2NUM(SIZE_OF_YOUR_STRUCTURE);
VALUE ptr = rb_class_new_instance(2, args, rb_cFiddlePointer);
xfree(args);
return ptr;

After linking the function to an actual Ruby method, you can then call it to get a sized pointer to the internal structure in memory.

Rust - Wrapping FFI Pointers

Found a Solution:

Using pub (crate), the internal pointer can be made accessible only to code in the crate and not to outside users.



Related Topics



Leave a reply



Submit