1 个不稳定版本
0.1.0 | 2024年7月30日 |
---|
696 在 Rust 模式 中排名
每月123次下载
21KB
144 代码行
x-selfref
这基本上是对 MIT 许可证的 selfref 库(由另一位作者)的一个复制/分支,我增加了一些功能。
selfref 介绍
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 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>>>,
# }
use xselfref::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 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>>>,
# }
# use xselfref::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.
use xselfref::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 xselfref::Holder;
use xselfref::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 不可靠,我们目前需要以下功能来支持在 xselfref::opaque!
中的 T: ?Sized
alloc
- 为T: ?Sized
提供xselfref::opaque!
,由Box
实现。nightly
- 为T: ?Sized
提供xselfref::opaque!
,通过在PhantomData
周围添加一个包装器来解决上述问题。我们称其为 "PhantomDrop"。
当同时启用这两个功能时,nightly
将接管并始终使用包装器。由于生成的 UB 检查已经是死代码,因此这不会带来显著差异,但 PhantomDrop
不依赖于 alloc
,并且可以在 no_std
环境中使用。
如果不使用任何功能,则需要通过 unsafe
方式实现 Opaque
以支持 T: ?Sized
。
请注意,我们默认不会启用任何功能!我们假设大多数人不是来使用这个 crate 的 T: ?Sized
支持的,因此这些是 crate 依赖的最佳默认设置。如果他们确实需要 ?Sized
支持的话,他们只需启用其中之一(可能是 alloc
)。