15个不稳定版本 (3个破坏性更新)
0.4.3 | 2023年9月5日 |
---|---|
0.4.2 | 2023年1月25日 |
0.4.0 | 2022年12月12日 |
0.3.0 | 2022年12月4日 |
0.1.4 | 2022年6月23日 |
在Rust模式中排名第783位
每月下载量81次
在srce中使用
30KB
177 行
selfref
请参考此crate的最高级别文档。
lib.rs
:
Rust中自引用结构的实验性方法。
此crate提供了一种自引用结构的替代方法,而不是提供一个宏或框架,您在其中定义一个自引用结构,并为您处理所有细节,我们试图公开抽象和构建块,以便在安全Rust中使自引用结构工作得更好。
例如,一个Holder
是自引用结构的安全包装,提供用于构建和操作自引用结构的API。然而,与其他自引用crate不同,它不指定结构的支持存储。使用Opaque
特性来识别用于Holder
的自引用结构——由于Rust不支持高阶类型(HKTs),此crate使用泛型关联类型(GATs)作为解决方案。
要使用此crate,首先使用纯Rust定义一个自引用结构
use std::cell::Cell;
// Your self-referential struct.
struct MySelfRefStruct<'this> {
// Rust uses RAII-like struct construction, as a result this must be
// somehow initialized after the struct. We can use an Option in a Cell
// for this.
this: Cell<Option<&'this MySelfRefStruct<'this>>>,
}
然后,定义一个类型以实现Opaque
。可以使用opaque
宏自动完成此操作
use selfref::opaque;
// A "marker type" that implements `Opaque`.
// This follows the "type family" GAT pattern.
struct MySelfRefStructKey;
opaque! {
impl Opaque for MySelfRefStructKey {
type Kind<'this> = MySelfRefStruct<'this>;
}
}
// Alternatively, it is possible to implement `Opaque` on, for example,
// `MySelfRefStruct<'static>`, but the added lifetime adds verbosity which
// may be considered unnecessary/undesired.
现在您可以为它构造一个Holder
并为其选择一个存储。例如,在Box
use selfref::Holder;
fn main() {
// first, construct the struct
let holder = Box::pin(Holder::<'_, MySelfRefStructKey>::new_with(
|foo| foo.build({
MySelfRefStruct {
this: Cell::new(None)
}
})
));
// then, build the self-reference
holder.as_ref().operate_in(
|this| {
this.this.set(Some(this.get_ref()));
}
);
}
示例
这是一个从外部借用生命周期的更复杂示例
use core::cell::Cell;
use core::marker::PhantomData;
use core::pin::Pin;
use selfref::Holder;
use selfref::opaque;
struct Foo<'a, 'b: 'a> {
foo: Cell<Option<&'a Foo<'a, 'b>>>,
t: &'b str,
}
struct FooKey<'b>(PhantomData<&'b str>);
opaque! {
impl['b] Opaque for FooKey<'b> {
type Kind<'a> = Foo<'a, 'b>;
}
}
fn main() {
// a non-'static &str
let stack_array: [u8; 5] = *b"hello";
let stack_str = core::str::from_utf8(&stack_array).unwrap();
// construct the struct
let holder = Box::pin(Holder::<'_, FooKey<'_>>::new_with(|foo| {
foo.build(Foo {
foo: Default::default(),
t: stack_str,
})
}));
holder.as_ref().operate_in(|foo| {
foo.foo.set(Some(foo.get_ref()));
});
}
功能
由于PhantomData不安全,我们目前需要以下功能来在selfref::opaque!
中支持T: ?Sized
alloc
- 对于T: ?Sized
,提供了selfref::opaque!
,由Box
提供。nightly
- 对于T: ?Sized
,由PhantomData
的包装提供,解决了上述问题。我们称之为 "PhantomDrop"。
当同时启用这两个功能时,nightly
将接管并始终使用包装。由于生成的 UB 检查本身就是死代码,因此这不会产生重大差异,但 PhantomDrop
不依赖于 alloc
,并且可以在 no_std
环境中使用。
如果不使用任何功能,则需要 T: ?Sized
支持,需要不安全地实现 Opaque
。
注意,我们默认不启用任何功能!我们假设大多数人不会因为 T: ?Sized
支持而使用这个 crate,所以这些是 crate 依赖的最佳默认设置。如果他们需要 ?Sized
支持,他们只需启用其中之一(可能是 alloc
)。
依赖关系
~48KB