Rust 我怎样才能在拥有的指针周围公开一个安全的包装器?
我正在包装一个有两个结构的C库:一个有指向另一个的指针Rust 我怎样才能在拥有的指针周围公开一个安全的包装器?,rust,Rust,我正在包装一个有两个结构的C库:一个有指向另一个的指针 struct StructA { void * some_mem; }; struct StructB { void * some_mem; struct StructA * some_struct; }; 这两个结构都有内存,所以我的包装器都有构造函数和析构函数 struct StructA(*mut c_void); impl StructA { fn new() -> Self {
struct StructA {
void * some_mem;
};
struct StructB {
void * some_mem;
struct StructA * some_struct;
};
这两个结构都有内存,所以我的包装器都有构造函数和析构函数
struct StructA(*mut c_void);
impl StructA {
fn new() -> Self {
StructA(c_constructor())
}
}
impl Drop for StructA {
fn drop(&mut self) {
let StructA(ptr) = self;
c_destructor(ptr);
}
}
还有一个函数,它获取指向StructB
的指针,并返回指向StructA
的指针:
const struct StructA * get_struct(const struct StructB * obj);
此函数的用户不应释放返回的指针,因为当用户释放obj
时,指针将被释放
如何包装此函数?问题是StructB
的析构函数释放了所有内存,包括StructA
的内存。因此,如果我对get_struct
的包装返回一个对象,那么包装的StructA
将被释放两次(对吗?)。它可以返回对对象的引用,但该对象将位于何处
我可以为StructA
创建单独的结构,这取决于它是独立的,是否需要释放,或者它是否是引用,但我希望这是不必要的
我可以根据StructA是独立的并且需要释放,或者它是引用,为StructA设置单独的结构,但我希望这是不必要的
这是必要的。拥有的StructA*
和借用的StructA*
之间的区别与框
和&T
之间的区别完全相同。它们都是“指针”,但语义完全不同
沿着这些思路的东西可能就是你想要的:
use std::marker::PhantomData;
struct OwnedA(*mut c_void);
impl Drop for OwnedA {
fn drop(&mut self) { }
}
impl OwnedA {
fn deref(&self) -> RefA { RefA(self.0, PhantomData) }
}
struct RefA<'a>(*mut c_void, PhantomData<&'a u8>);
struct OwnedB(*mut c_void);
impl Drop for OwnedB {
fn drop(&mut self) { }
}
impl OwnedB {
fn get_a(&self) -> RefA { RefA(get_struct(self.0), PhantomData) }
}
使用std::marker::PhantomData;
结构所有者(*多个c_void);
针对OwnedA的impl Drop{
fn drop(&mut self){}
}
impl OwnedA{
fn deref(&self)->RefA{RefA(self.0,PhantomData)}
}
结构重构);
结构所有者B(*多个c_void);
针对OwnedB的impl Drop{
fn drop(&mut self){}
}
impl-OwnedB{
fn get_a(&self)->RefA{RefA(get_struct(self.0),PhantomData)}
}
特别值得注意的是,RefA上的lifetime参数允许编译器确保在释放支持结构后不使用RefA
我可以根据StructA是独立的并且需要释放,或者它是引用,为StructA设置单独的结构,但我希望这是不必要的
我相信这将是公认的模式。对于备份,我要指出一个事实,这是Rust库中的正常模式&str
和String
,和[T]
和Vec
,Path
和PathBuf
,可能还有很多我想不到的东西
好消息是,您可以使用与这些对类似的模式,利用Deref
或DerefMut
调用共享实现:
use std::ops::{Deref, DerefMut};
enum RawFoo {}
fn c_foo_new() -> *const RawFoo { std::ptr::null() }
fn c_foo_free(_f: *const RawFoo) {}
fn c_foo_count(_f: *const RawFoo) -> u8 { 42 }
fn c_foo_make_awesome(_f: *const RawFoo, _v: bool) { }
struct OwnedFoo(Foo);
impl OwnedFoo {
fn new() -> OwnedFoo {
OwnedFoo(Foo(c_foo_new()))
}
}
impl Drop for OwnedFoo {
fn drop(&mut self) { c_foo_free((self.0).0) }
}
impl Deref for OwnedFoo {
type Target = Foo;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl DerefMut for OwnedFoo {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
struct Foo(*const RawFoo);
impl Foo {
fn count(&self) -> u8 { c_foo_count(self.0) }
fn make_awesome(&mut self, v: bool) { c_foo_make_awesome(self.0, v) }
}
fn main() {
let mut f = OwnedFoo::new();
println!("{}", f.count());
f.make_awesome(true);
}
然后,当您从另一个对象获得借用的指针时,只需将其包装在&Foo
:
use std::mem;
fn c_bar_foo_ref() -> *const RawFoo { std::ptr::null() }
// Ignoring boilerplate for wrapping the raw Bar pointer
struct Bar;
impl Bar {
fn new() -> Bar { Bar }
fn foo(&self) -> &Foo {
unsafe { mem::transmute(c_bar_foo_ref()) }
}
fn foo_mut(&mut self) -> &mut Foo {
unsafe { mem::transmute(c_bar_foo_ref()) }
}
}
fn main() {
let mut b = Bar::new();
println!("{}", b.foo().count());
b.foo_mut().make_awesome(true);
// Doesn't work - lifetime constrained to Bar
// let nope = Bar::new().foo();
}