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
Gets.Chomp Without Moving to a New Line
How to Use H2 as Embedded Database in Postgres-Compat Mode, from Jruby/Rails
Ruby Outputting to the Same Line as the Previous Output
Require Ruby File Without .Rb Extension
How to Refactor Openssl Pkcs5_Keyivgen in Ruby
Cancan Abilities in Separate File
Writing Ruby Console Output to Text File
How to Figure Out Which Step I'Ve Just Executed in Cucumber's Afterstep Hook
How to Parse Xml Nodes to CSV with Ruby and Nokogiri
Ruby on Rails: Params Is Nil. Undefined Method '[]' for Nil:Nilclass
Unexpected Value of _Callee_ When Including a Module - Is This a Ruby Bug
How to Get Error Messages from Ruby Threads
Ruby -- Capitalize First Letter of Every Sentence in a Paragraph
Ruby on Rails: Creating a Model Entry with a Belongs_To Association
Include Erb Delimiters Inside of a String in an Erb Block
Rails Form Object with Reform-Rails with Collections Not Working or Validating