Подтвердить что ты не робот

Можно ли использовать Fiddle для передачи или возврата структуры в собственный код?

Я хотел бы использовать Fiddle для доступа к собственной библиотеке, скомпилированной из кода Rust. C-представление структуры очень просто, это всего лишь указатель и длина:

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);

Однако все примеры, которые я могу найти, принимают или возвращают указатели на структуры, а не сами структуры. Я бы хотел избежать двойной косвенности, если это вообще возможно.

Я заимствовал пример из Fiddle::Importer documentation. Однако я не вижу, как правильно вызвать метод extern со структурой вместо указателя на структуру:

require 'fiddle'
require 'fiddle/import'

module LibSum
  extend Fiddle::Importer
  dlload './libsum.so'
  extern 'double sum(double*, int)'
  extern 'double split(double)'
end

Примечание

Fiddle не, как FFI gem. Fiddle является компонентом стандартной библиотеки Ruby и не предоставляется в качестве отдельного драгоценного камня. Эти связанные вопросы относятся к драгоценности FFI, а не к Fiddle:

4b9b3361

Ответ 1

Я просмотрел документацию Fiddle, и, как я вижу, это невозможно, поскольку даже в определении основной функции Fiddle::Function.new для этого требуются аргументы, которые может обрабатывать Fiddle::CParser. Я проделал различные тесты и сделал это, мне пришлось преобразовать ваш код в нечто вроде этого:

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

Я пришел к тому, что Fiddle может работать с простыми типами, но ему нужно использовать типы struct и union, которые будут переданы с использованием ссылок. Тем не менее у него есть обертки для этих классов. Также эти оболочки наследуются от Fiddle::Pointer, что приводит нас к выводу, что они хотят, чтобы мы использовали указатели для этих типов данных.

Если вам нужна дополнительная информация об этом или вы хотите добавить эту функциональность, вы можете пройти через их git репо.