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位

Download history 214/week @ 2024-03-08 25/week @ 2024-03-15 8/week @ 2024-03-29 2/week @ 2024-04-05 2/week @ 2024-04-12 3/week @ 2024-04-19

每月下载量81
srce中使用

MIT/Apache

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