我正在编写一个使用 的库NativeCall,如果能够Hash从导出函数返回 Raku 对我来说会非常方便。我怎样才能做到这一点?
例如,在 Ruby 中,如果我想Hash从 C 返回 a,我会这样做:
#include "ruby.h"
VALUE make_hash() {
VALUE hash = rb_hash_new();
return hash;
}
Run Code Online (Sandbox Code Playgroud)
我有兴趣看看这是否可以完成,我在想也许我需要使用 MoarVM 标头或其他东西。但我不确定。
我想做的是编写一个 C 函数,它接受一个 String 来做一些事情,然后返回一个 Raku 哈希。
如果能够从导出函数返回 Raku Hash 对我来说会非常方便
一种解决方法是让 C 函数返回一个包含键和值的结构,然后编写一个 Raku 包装器,将其转换为 Raku 哈希,如下所示:
use v6;
use NativeCall;
constant LIB = ('./libmylib.so');
class HInfo is repr('CStruct') is export {
has Str $.key1;
has num64 $.value1;
has Str $.key2;
has num64 $.value2;
}
sub foo_(Str--> HInfo) is native(LIB) is symbol('foo') { * }
sub foo(Str $str --> Hash) {
my HInfo $hinfo = foo_($str);
my %h;
%h{$hinfo.key1} = $hinfo.value1;
%h{$hinfo.key2} = $hinfo.value2;
return %h;
}
my %h = foo("bar");
dd %h;
Run Code Online (Sandbox Code Playgroud)
我在这里为 Rust 做了大致的操作(这是一些 Raku-Rust Nativecall 代码示例的集合,而不是模块)...
首先是乐:
## Rust FFI Omnibus: Objects
## http:##jakegoulding.com/rust-ffi-omnibus/objects/
class ZipCodeDatabase is repr('CPointer') {
sub zip_code_database_new() returns ZipCodeDatabase is native($n-path) { * }
sub zip_code_database_free(ZipCodeDatabase) is native($n-path) { * }
sub zip_code_database_populate(ZipCodeDatabase) is native($n-path) { * }
sub zip_code_database_population_of(ZipCodeDatabase, Str is encoded('utf8'))
returns uint32 is native($n-path) { * }
method new {
zip_code_database_new
}
submethod DESTROY { # Free data when the object is garbage collected.
zip_code_database_free(self);
}
method populate {
zip_code_database_populate(self)
}
method population_of( Str \zip ) {
zip_code_database_population_of(self, zip);
}
}
my \database = ZipCodeDatabase.new;
database.populate;
my \pop1 = database.population_of('90210');
my \pop2 = database.population_of('20500');
say pop1 - pop2;
Run Code Online (Sandbox Code Playgroud)
然后是铁锈:
// Rust FFI Omnibus: Objects
// http://jakegoulding.com/rust-ffi-omnibus/objects/
pub struct ZipCodeDatabase {
population: HashMap<String, u32>,
}
impl ZipCodeDatabase {
fn new() -> ZipCodeDatabase {
ZipCodeDatabase {
population: HashMap::new(),
}
}
fn populate(&mut self) {
for i in 0..100_000 {
let zip = format!("{:05}", i);
self.population.insert(zip, i);
}
}
fn population_of(&self, zip: &str) -> u32 {
self.population.get(zip).cloned().unwrap_or(0)
}
}
#[no_mangle]
pub extern "C" fn zip_code_database_new() -> *mut ZipCodeDatabase {
Box::into_raw(Box::new(ZipCodeDatabase::new()))
}
#[no_mangle]
pub extern "C" fn zip_code_database_free(ptr: *mut ZipCodeDatabase) {
if ptr.is_null() {
return;
}
unsafe {
Box::from_raw(ptr);
}
}
#[no_mangle]
pub extern "C" fn zip_code_database_populate(ptr: *mut ZipCodeDatabase) {
let database = unsafe {
assert!(!ptr.is_null());
&mut *ptr
};
database.populate();
}
#[no_mangle]
pub extern "C" fn zip_code_database_population_of(
ptr: *const ZipCodeDatabase,
zip: *const c_char,
) -> u32 {
let database = unsafe {
assert!(!ptr.is_null());
&*ptr
};
let zip = unsafe {
assert!(!zip.is_null());
CStr::from_ptr(zip)
};
let zip_str = zip.to_str().unwrap();
database.population_of(zip_str)
}
Run Code Online (Sandbox Code Playgroud)
显然,C 方面的事情需要完全不同,但希望这能提供足够的线索。
| 归档时间: |
|
| 查看次数: |
225 次 |
| 最近记录: |