Можно ли использовать 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. . Однако я не вижу, как правильно вызвать метод 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. Fiddle является компонентом стандартной библиотеки Ruby и не предоставляется как отдельный гем. Эти связанные вопросы относятся к драгоценному камню FFI, а не к Fiddle:


person Shepmaster    schedule 18.05.2015    source источник
comment
Интересный вопрос, но я сомневаюсь, что это возможно, поскольку FFI (для которого Fiddle является оболочкой), похоже, не поддерживает передачу структур напрямую, см. Раздел «Аргументы функции и возвращаемые значения» в этот документ (на японском языке, я читал перевод Google), и если вы ожидаете некоторого повышения производительности, вы вряд ли получите что-нибудь существенное - переменные ruby ​​- это указатели на структуру с данными (RBasic и подклассы) или даже еще один указатель оттуда на фактические данные в куче.   -  person Eugene Petrov    schedule 28.06.2015
comment
Также список поддерживаемых типов в сигнатурах функций можно взять из _ 1_.   -  person Eugene Petrov    schedule 28.06.2015


Ответы (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.

person Glupo    schedule 30.06.2015