How to pass struct as argument of function
nerzh opened this issue · 5 comments
Hi, sorry for my english. I will show the problem with examples:
header.h
typedef struct {
const char* content;
uint32_t len;
} tc_string_data_t;
typedef struct tc_string_handle_t tc_string_handle_t;
tc_string_handle_t* tc_create_context(tc_string_data_t config);
tc_string_data_t tc_read_string(const tc_string_handle_t* handle);
void tc_destroy_string(const tc_string_handle_t* handle);
How its work in ruby with gem ffi
require "json"
require "ffi"
module Binding
class TcStringDataT < FFI::Struct
layout :content, :pointer,
:len, :uint32
end
end
module Binding
extend FFI::Library
ffi_lib "/path_to_lib"
def self.setup_bindings
attach_function :tc_create_context, [TcStringDataT.by_value], :pointer
attach_function :tc_read_string, [:pointer], TcStringDataT.by_value
attach_function :tc_destroy_string, [:pointer], :void
end
end
config_json = {network: {endpoints: ["http://some_url"]}}.to_json
# make struct
data_struct = Binding::TcStringDataT.new
data_struct[:content] = FFI::MemoryPointer.from_string(config_json)
data_struct[:len] = config_json.bytesize
# create context
string_ref = Binding.tc_create_context(data_struct)
# read context response
result_data_struct = Binding.tc_read_string(string_ref)
result_string = result_data_struct[:content].read_string(result_data_struct[:len])
# destroy ref
Binding.tc_destroy_string(string_ref)
ffi gem works, but sometimes i get segmentation fault :(
So I decided to try to do it with fiddle !
But how ? How to do it with fiddle ? I climbed the entire Internet. I haven't found a single example of how to pass a struct to a function. There are only very few examples of how to pass ordinary primitives and not a single example of how to pass a structure. I have tried many options and still have not been able to achieve a result. Please help me !!! Write an example of calling these functions and passing arguments to them. Really looking forward to the answer.
Here is what I do with fidl:
require 'fiddle'
require 'fiddle/import'
require 'json'
module TestFiddle
extend Fiddle::Importer
extend Fiddle::CParser
dlload('/lib_client.dylib')
TcStringDataT = struct [
'const char* content',
'uint len'
]
# tc_string_handle_t* tc_create_context(tc_string_data_t config);
# extern 'TcStringDataT* tc_create_context(TcStringDataT config)' ## unknown type TcStringDataT
extern 'TcStringDataT* tc_create_context(TcStringDataT* config)' ## OK
# tc_string_data_t tc_read_string(const tc_string_handle_t* handle);
# extern 'TcStringDataT tc_read_string(const TcStringDataT* handle)' ## unknown type TcStringDataT
extern 'TcStringDataT* tc_read_string(const TcStringDataT* handle)' ## OK
# void tc_destroy_string(const tc_string_handle_t* handle)
# extern 'void tc_destroy_string(const TcStringDataT handle)' ## unknown type TcStringDataT
extern 'void tc_destroy_string(const TcStringDataT* handle)' ## OK
end
config_json = {network: {endpoints: ["http://some_url"]}}.to_json
struct = TestFiddle::TcStringDataT.malloc
struct.content = Fiddle::Pointer.to_ptr(config_json)
struct.len = config_json.bytesize
# How to pass this struct ???
ctx_ptr = TestFiddle.tc_create_context(struct) ## ERROR ERROR ERROR, many many zeros and ones
string_ptr = TestFiddle.tc_read_string(ctx_ptr)
struct = Test::TcStringDataT.new(string_ptr)
p struct.content.to_s
please help me with this 🙏
Hi, maybe it is impossible 🫣 ? Then please tell me about it, then I will not try to make the code work 🕰
It's impossible for now...
It's impossible for now...
oh, that's sad to hear 😔 Thanks for your answer 🤝
I also ran into this, trying to wrap a library that has a function that requires a struct passed by value. I could get around it with some type erasure, if only it was shorter -- a void* is 8 bytes and the struct is 16. Is this something that is not supported by libffi, or just not by fiddle?
It's just not implemented yet. We can do this by using FFI_TYPE_STRUCT
.