Възможно ли е да се използва 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 gem. 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
Също така списъкът с поддържаните типове във функционалните сигнатури може да бъде взет от parse_ctype функция.   -  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 repo.

person Glupo    schedule 30.06.2015