FFI锈性状传递对象作为上下文来调用的回调 [英] Rust FFI passing trait object as context to call callbacks on

查看:131
本文介绍了FFI锈性状传递对象作为上下文来调用的回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,我想实现如下:


  1. C调用到铁锈

  2. 防锈回调到c和注册一个用户定义的特征对象
  3. 回调
  4. C调用到锈与上下文

  5. 防锈调用回调上下文(特质对象)

我一直在玩弄它颇有几分。我得到了很远,但还是不太有。

I've been playing around with it quite a bit. I got quite far, but still not quite there.

C位:

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

void *global_ctx;

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

int main(void) {
    void *thing = dlopen("thing/target/debug/libthing.dylib", RTLD_NOW | RTLD_GLOBAL);
    if (!thing) {
        printf("error: %s\n", dlerror());
        return 1;
    }
    void (*rust_function)(void) = dlsym(thing, "rust_function");
    void (*rust_cb)(void*) = dlsym(thing, "rust_cb");
    printf("rust_function = %p\n", 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的函数签名改为

One Solution: - Change the function signature of "rust_cb" to

pub extern fn rust_cb(context: *mut MyFoo)

但是这不是我想要的,因为我试图创造一个安全的包装,只知道听众的特点

but that's not what I want, as I'm trying to create a safe wrapper that only knows the trait of the listener

任何帮助AP preciated

Any help appreciated

PS:我的假设是,它出现segfaults,因为编译器不知道的特质偏移回调美孚,它需要实际的对象,以确定它在哪里。但我不知道如何解决的。

PS: my assumption is that it segfaults, because the compiler doesn't know the offset of callback on the trait Foo, it needs the actual object to determine where it is. but then i have no idea how to work around that

推荐答案

所以,如果你需要重新present的无效* ,您可以使用此:

So, if you need to represent the Foo as a void *, you can use this:

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位)的尺寸。在这个例子中,是不是一个特质的对象,它是一个动态调整型(即具有可变大小类型,如 STR )。 盒及LT;富&GT; 是一个特质的对象。 盒&LT;盒&LT;富&GT;&GT; 既不是特质的对象或动态大小的类型,它是具有尺寸为指针同一个类型,这就是为什么我们需要在这里使用它,因为我们希望把它转换成一个无效*

I think you may be misunderstanding what a trait object is. A trait object is a type that is the size of two pointers (so, 128 bits on a 64-bit system). In this example, Foo is not a trait object, it is a dynamically sized type (i.e. a type which has a variable size, such as str). Box<Foo> is a trait object. Box<Box<Foo>> is neither a trait object or a dynamically sized type, it is a type that has the same size as a pointer, which is why we need to use it here since we want to convert it into a void *.

我把它称为泄漏,因为当你调用箱:: into_raw ,你都渗出的无论是在中,这意味着你是负责记忆为确保析构函数(即挂断实施)被调用。

I call it "leaking" because when you call Box::into_raw, you are leaking the memory of whatever is in the box, which means that that you are responsible for making sure the destructor (the Drop implementation) gets called.

这篇关于FFI锈性状传递对象作为上下文来调用的回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆