根据我的这个问题的答案:如何在通过C++创建的Rust代码中保存Rust对象?我可以将 Rust 中在 a 中分配的东西传递回 C Box
,然后再次将其作为对 的引用接收回来&T
,因为 Rust 分配的Sized
结构遵循 C ABI。
我想做同样的事情,但现在Rc<RefCell<T>>
。我应该返回 aBox
到吗Rc<RefCell<T>>
?我猜它不会,因为Rc
没有实现,这是根据Box 页面所Sized
必需的。所以这行不通:T
Box<T>
#[no_mangle]
pub extern "C" fn foo_new() -> Box<Rc<RefCell<T>>> {
Box::new(Foo { glonk: false })
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?基本上,我需要创建一个可以被许多人访问的 Rust 结构,并且可以被其中之一可变地借用。这就是我选择的原因Rc<RefCell<T>>
。是否有另一种类型的结构可以满足我的要求并且对 C 语言友好?
它们实现了智能指针Rc<T>
和Box<T>
确实大小的类型Sized
。此信息未在文档中提供,可能是因为 的特殊性质Sized
:它始终自动派生所有适用的类型,并且无法添加或取消该实现(与 和 不同Send
)Sync
。
排除了这一点,将另一个智能指针封装到Box
. 如果打算将实际智能指针 ( Rc
) 跨过 C FFI 边界并返回,则只需记住一件事: an 的布局Rc<T>
与原始指针不兼容,即使T
是Sized
(与 不同Box<T>
)。
因此,我们需要将其显式地转换为原始指针并返回。函数into_raw
和from_raw
也可用于Rc
.
/// create a new Foo and give it to caller
#[no_mangle]
pub extern "C" fn foo_new() -> *const RefCell<Foo> {
Rc::into_raw(Rc::new(RefCell::new(Foo { glonk: false })))
}
/// clone the pointers into two
#[no_mangle]
pub extern "C" fn foo_clone(foo: *const RefCell<Foo>) -> (*const RefCell<Foo>, *const RefCell<Foo>) {
unsafe {
let ptr = Rc::from_raw(foo);
let c = Rc::clone(ptr);
(ptr, c)
}
}
/// get a property of a Foo without returning ownership
#[no_mangle]
pub extern "C" fn foo_glonk(foo: *const RefCell<Foo>) -> bool {
unsafe { (*foo).borrow().glonk }
}
/// return ownership of the Foo,
/// so it can be freed in Rust-land
#[no_mangle]
pub extern "C" fn foo_return(foo: *const RefCell<Foo>) {
let _ = Rc::from_raw(foo);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
596 次 |
最近记录: |