Est-il possible d'utiliser Fiddle pour passer ou retourner une structure au code natif?

j'aimerais utiliser Fiddle pour accéder à une bibliothèque native compilée à partir du code Rust. La représentation en C de la structure est très simple, elle n'est qu'un pointeur et une longueur:

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

cependant, tous les exemples que je peux trouver acceptent ou renvoient des pointeurs pour les structures, et pas les structures elles-mêmes. J'aimerais éviter la double indirection si possible.

j'ai emprunté un exemple au Fiddle::Importer documentation . Cependant, je ne vois pas comment appeler correctement la méthode extern avec une structure au lieu d'un pointeur vers une structure:

require 'fiddle'
require 'fiddle/import'

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

Note

Violon est pas le même que le FFI gem . Fiddle est une composante de la bibliothèque Ruby standard, et n'est pas fourni comme un joyau séparé. Ces questions connexes se réfèrent au gem, et de ne pas jouer du Violon:

21
demandé sur Community 2015-05-18 03:05:35

1 réponses

j'ai parcouru la documentation Fiddle et comme je peux le voir, il n'est pas possible puisque même dans la définition de la fonction de base Fiddle::Function.new il nécessite args que Fiddle::CParser peut gérer. J'ai fait divers tests et pour que ça marche, j'ai dû transformer votre code en quelque chose comme ça:

essai2.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

ce que je suis venu à est que Fiddle peut fonctionner avec des types simples, mais les besoins Les types struct et union doivent être transmis à l'aide de références. Il y a encore des papiers pour cette classe. En outre ces enveloppes sont héritées de Fiddle::Pointer ce qui nous amène à conclure qu'ils veulent que nous utilisions des pointeurs pour ces types de données.

si vous voulez plus de détails à ce sujet ou vous voulez ajouter cette fonctionnalité, vous pouvez passer par leur git repo .

11
répondu Glupo 2015-06-30 09:53:16