加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Rust FFI将trait对象作为上下文传递给调用回调

发布时间:2020-12-16 10:00:20 所属栏目:百科 来源:网络整理
导读:好的,我正在尝试实现以下目标: C召唤生锈 rust回调c并在用户定义的trait对象上注册回调 c调用上下文生锈 rust调用上下文的回调(trait对象) 我一直在玩它很多.我走得很远,但仍然没有那么远. C位: #include dlfcn.h#include stdio.hvoid *global_ctx;void c_
好的,我正在尝试实现以下目标:

> C召唤生锈
> rust回调c并在用户定义的trait对象上注册回调
> c调用上下文生锈
> rust调用上下文的回调(trait对象)

我一直在玩它很多.我走得很远,但仍然没有那么远.

C位:

#include <dlfcn.h>
#include <stdio.h>

void *global_ctx;

void c_function(void* ctx) {
    printf("Called c_functionn");
    global_ctx = ctx;
}

int main(void) {
    void *thing = dlopen("thing/target/debug/libthing.dylib",RTLD_NOW | RTLD_GLOBAL);
    if (!thing) {
        printf("error: %sn",dlerror());
        return 1;
    }
    void (*rust_function)(void) = dlsym(thing,"rust_function");
    void (*rust_cb)(void*) = dlsym(thing,"rust_cb");
    printf("rust_function = %pn",rust_function);
    rust_function();

    rust_cb(global_ctx);
}

生锈位:

extern crate libc;


pub trait Foo {
    fn callback(&self);
}

extern {
    fn c_function(context: *mut libc::c_void);
}

pub struct MyFoo;
impl Foo for MyFoo {
    fn callback(&self) {
        println!("callback on trait");
    }
}

#[no_mangle]
pub extern fn rust_cb(context: *mut Foo) {
    unsafe {
        let cb:Box<Foo> = Box::from_raw(context);
        cb.callback();
    }
}

#[no_mangle]
pub extern fn rust_function() {
    println!("Called rust_function");
    let tmp = Box::new(MyFoo);
    unsafe {
        c_function(Box::into_raw(tmp) as *const Foo as *mut libc::c_void);
    }
}

问题:

>当我尝试在“rust_cb”中对特征对象调用“回调”时,我的程序会出现段错误

一解决方案:
? – 将“rust_cb”的功能签名更改为

pub extern fn rust_cb(context: *mut MyFoo)

但这不是我想要的,因为我正在尝试创建一个只知道监听器特性的安全包装器

任何帮助赞赏

PS:我的假设是它是segfaults,因为编译器不知道特征Foo上的回调偏移量,它需要实际的对象来确定它的位置.但后来我不知道如何解决这个问题

解决方法

所以,如果你需要将Foo表示为void *,你可以使用:

extern crate libc;

pub trait Foo {
    fn callback(&self);
}

extern {
    fn c_function(context: *mut libc::c_void);
}

pub struct MyFoo;
impl Foo for MyFoo {
    fn callback(&self) {
        println!("callback on trait");
    }
}

#[no_mangle]
pub extern fn rust_cb(context: *mut Box<Foo>) {
    unsafe {
        let cb: Box<Box<Foo>> = Box::from_raw(context);
        cb.callback();
    }
}

#[no_mangle]
pub extern fn rust_function() {
    println!("Called rust_function");
    let tmp: Box<Box<Foo>> = Box::new(Box::new(MyFoo));
    unsafe {
        c_function(Box::into_raw(tmp) as *mut Box<Foo> as *mut libc::c_void);
    }
}

我想你可能误解了特质对象是什么.特征对象是两个指针大小的类型(因此,64位系统上为128位).在这个例子中,Foo不是特征对象,它是动态大小的类型(即具有可变大小的类型,例如str).盒及LT;富>是一个特质对象.盒及LT;盒及LT;富>>既不是特征对象也不是动态大小的类型,它是一个与指针大小相同的类型,这就是为什么我们需要在这里使用它,因为我们想将它转换为void *.

我将其称为“泄漏”,因为当您调用Box :: into_raw时,您正在泄漏框中所有内容的内存,这意味着您负责确保调用析构函数(Drop实现).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读