2015-05-18 42 views
21

Tôi muốn sử dụng Fiddle để truy cập thư viện gốc được biên dịch từ mã Rust. Các đại diện C của struct là rất đơn giản, nó chỉ là một con trỏ và chiều dài:Có thể sử dụng Fiddle để chuyển hoặc trả về cấu trúc cho mã gốc không?

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

Tuy nhiên, tất cả các ví dụ tôi có thể tìm thấy chấp nhận hoặc trả lại con trỏ đến cấu trúc, và không phải là cấu trúc chính mình. Tôi muốn tránh sự bỏ cặp đôi nếu có thể.

Tôi đã mượn ví dụ từ Fiddle::Importer documentation. Tuy nhiên, tôi không thấy làm thế nào để đúng cách gọi phương thức extern với một cấu trúc thay vì một con trỏ đến một cấu trúc:

require 'fiddle' 
require 'fiddle/import' 

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

Note

Fiddle là không giống như FFI gem. Fiddle là một thành phần của thư viện chuẩn của Ruby, và không được cung cấp như một viên ngọc riêng biệt. Những câu hỏi liên quan tham khảo các viên ngọc FFI, và không thay vì chỉ violong:

+0

Câu hỏi thú vị, nhưng tôi nghi ngờ có thể là FFI (Fiddle là trình bao bọc) dường như không hỗ trợ trực tiếp cấu trúc truyền, xem phần "Đối số chức năng và giá trị trả về" của [tài liệu này] (http: // fistfvck .sakura.ne.jp/ruby ​​/ rurima-2.1.0/library/fiddle.html) (tiếng Nhật, tôi đã đọc bản dịch của google) và nếu bạn mong đợi một số hiệu suất tăng bạn sẽ rất khó có được bất kỳ điều gì đáng kể - các biến của ruby ​​là con trỏ đến cấu trúc với một dữ liệu ('RBasic' và các lớp con), hoặc thậm chí một con trỏ khác từ đó đến dữ liệu thực tế trong heap. –

+0

Ngoài ra, danh sách các loại được hỗ trợ trong chữ ký chức năng có thể được lấy từ ['parse_ctype'] (https://github.com/ruby/ruby/blob/c8b3f1b470e343e7408ab5883f046b1056d94ccc/ext/fiddle/lib/fiddle/cparser.rb#L120) chức năng. –

Trả lời

11

Tôi đã trải qua tài liệu Fiddle và như tôi có thể nhìn thấy nó là không thể vì ngay cả trong chức năng cốt lõi định nghĩa Fiddle::Function.new nó đòi hỏi args rằng Fiddle::CParser có thể xử lý. Tôi đã làm thử nghiệm khác nhau và để làm cho nó làm việc tôi đã phải thay đổi mã của bạn vào một cái gì đó như thế này:

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 

Những gì tôi đến là Fiddle có thể hoạt động với các loại đơn giản nhưng cần các loại structunion bằng cách sử dụng các tham chiếu. Nó vẫn có trình bao bọc cho các lớp này. Ngoài ra các trình bao bọc này được thừa kế từ Fiddle::Pointer điều gì đã dẫn chúng ta đến kết luận rằng chúng muốn chúng ta sử dụng con trỏ cho các kiểu dữ liệu này.

Nếu bạn muốn biết thêm chi tiết về điều này hoặc bạn muốn thêm chức năng này, bạn có thể đi qua their git repo.

Các vấn đề liên quan