ruby - ¿Es posible usar Fiddle para pasar o devolver una estructura a código nativo?
ffi (1)
He revisado la documentación de Fiddle y, como puedo ver, no es posible, ya que incluso en la definición de la función central Fiddle::Function.new
requiere Fiddle::CParser
pueda manejar Fiddle::CParser
. He hecho varias pruebas y, para hacer que funcione, tuve que transformar tu código en algo como esto:
prueba2.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
Lo que descubrí es que Fiddle
puede operar con tipos simples pero necesita que se pasen tipos de struct
y de union
usando referencias. Todavía tiene envoltorios para estas clases. Además, estos envoltorios se heredan de Fiddle::Pointer
lo que nos lleva a la conclusión de que quieren que usemos punteros para estos tipos de datos.
Si desea más detalles sobre esto o desea agregar esta funcionalidad, puede ir a través de su repositorio git .
Me gustaría usar Fiddle para acceder a una biblioteca nativa compilada desde el código Rust. La representación en C de la estructura es muy simple, es solo un puntero y una longitud:
typedef struct {
char *data;
size_t len;
} my_thing_t;
// Example function that somehow accepts a struct
void accepts_a_struct(my_thing_t thing);
// Example function that somehow returns a struct
my_thing_t returns_a_struct(void);
Sin embargo, todos los ejemplos que puedo encontrar aceptan o devuelven punteros a estructuras, y no las estructuras en sí. Me gustaría evitar la doble indirección si es posible.
He tomado prestado un ejemplo de la documentación de Fiddle::Importer
. Sin embargo, no veo cómo llamar correctamente al método extern
con una estructura en lugar de un puntero a una estructura:
require ''fiddle''
require ''fiddle/import''
module LibSum
extend Fiddle::Importer
dlload ''./libsum.so''
extern ''double sum(double*, int)''
extern ''double split(double)''
end
Nota
El violín no es lo mismo que la gema FFI . Fiddle es un componente de la biblioteca estándar de Ruby y no se proporciona como una gema separada. Estas preguntas relacionadas se refieren a la gema de FFI, y no a Fiddle:
- ¿Cómo envolver la función en el método Ruby FFI que toma struct como argumento?
- ¿Cómo especifico una estructura como el valor de retorno de una función en RubyFFI?