1 个不稳定版本

0.0.3 2024年4月30日
0.0.2 2022年7月16日
0.0.1 2022年6月29日

#330Rust 模式

Download history 134/week @ 2024-04-26 15/week @ 2024-05-03 2/week @ 2024-07-05

每月191 次下载

MIT/Apache

46KB
377

自拍

Cargo Documentation

一个轻量级自引用结构体库。无宏、无分配,且支持 #![no_std]

该包是实验性的,尚未准备好用于生产使用!

该包是一个实验,旨在创建简单且无分配的自引用结构体,这在实时音频环境中是必需的。

虽然这个库很小,并在 MIRI 下进行了广泛的测试,我相信它是安全的,但它尚未经过同行评审或得到足够的实际应用。

如果您愿意尝试它,请随时!欢迎对稳定性、可用性进行审查和提交 PR:自引用结构体是一个复杂的问题,我唯一有信心的地方是库的名称。

优势

已经存在其他自引用结构体库,但它们并不完全符合我的需求

  • 无宏Selfie 不会使用 proc-macros 或宏来创建自引用结构体。这允许快速编译时间,同时也有简单、IDE 友好的语法,不会干扰更复杂的场景。
  • 无分配:创建 Selfie 不会执行任何分配,实际上是一个零成本操作。 Selfie 结构体将拥有的指针和引用类型存储在彼此旁边,因此唯一的间接引用就是从已经存在的 owned 指针。这也意味着 Selfie 库完全是 #![no_std]
  • 对于拥有的类型几乎没有限制:拥有的类型的唯一要求是它位于一个可固定和稳定的指针后面(即实现 StableDeref)。标准库中的候选包括 &T&mut TBoxRcArcStringVec 以及其他,但任何外部库(如 basedrop)提供的指针也天生支持。
  • 引用类型没有限制Selfie 可以与任何与拥有类型有生命周期关系的类型一起使用,包括任何你自定义的类型(但需要一些样板代码,下面有示例)。
  • 支持可变自引用Selfie 还有一个 SelfieMut 变体,它允许使用固定的可变引用而不是简单的共享引用来构造引用。
  • 支持非静态指针Selfie 可以与任何生命周期相关联,允许“拥有”指针同时借用其他内容。
  • 支持级联自引用:由于 Selfie 可以是非静态的,并且引用类型没有限制,因此一个 Selfie 可以作为另一个 Selfie 中的引用类型!这允许创建复杂的自引用结构。

缺点

  • 需要一些样板代码:尽管 Selfie 本身没有太多的复杂性,因为它不依赖于宏,所以这种复杂性直接推给了库的用户。这使得在有些时候 Selfie 类型相当复杂,并且使用自定义引用类型时需要一些样板代码。
  • 引用类型可以被移动:如果您的引用类型被您的结构体中的另一个成员引用,这可能是一个问题,因为它还需要有一个稳定的地址。在当前版本的 Selfie 中,这需要多个指针(可能分配),尽管理论上可以合并到一个分配中。这可能在未来的 Selfie 变体中得到解决。

示例

缓存 String 子切片

use core::pin::Pin;
use selfie::{refs::Ref, Selfie};

let data: Pin<String> = Pin::new("Hello, world!".to_owned());
let selfie: Selfie<String, Ref<str>> = Selfie::new(data, |s| &s[0..5]);

assert_eq!("Hello", selfie.with_referential(|r| *r));
assert_eq!("Hello, world!", selfie.owned());

使用自定义引用类型

use std::pin::Pin;
use selfie::{refs::RefType, Selfie};

#[derive(Copy, Clone)]
struct MyReferentialType<'a>(&'a str);

struct MyReferentialTypeStandIn;

impl<'a> RefType<'a> for MyReferentialTypeStandIn {
  type Ref = MyReferentialType<'a>;
}

// MyReferentialType can now be used in Selfies!
let data = Pin::new("Hello, world!".to_owned());
let selfie: Selfie<String, MyReferentialTypeStandIn> = Selfie::new(data, |str| MyReferentialType(&str[0..5]));

assert_eq!("Hello", selfie.with_referential(|r| *r).0);

可变自引用

use core::pin::Pin;
use selfie::{refs::Mut, SelfieMut};

let data: Pin<String> = Pin::new("Hello, world!".to_owned());
let mut selfie: SelfieMut<String, Mut<str>> = SelfieMut::new(data, |s| &mut Pin::into_inner(s)[0..5]);

selfie.with_referential_mut(|s| s.make_ascii_uppercase());
selfie.with_referential(|s| assert_eq!("HELLO", *s));

// By dropping the referential part, we get back the access to the owned data
let data: String = Pin::into_inner(selfie.into_owned());
assert_eq!("HELLO, world!", &data);

级联 Selfies

use std::pin::Pin;
use selfie::refs::{Ref, SelfieRef};
use selfie::Selfie;

let data = Pin::new("Hello, world!".to_owned());
let selfie: Selfie<String, SelfieRef<Ref<str>, Ref<str>>> = Selfie::new(data, |str| {
    let substr = Pin::new(&str[0..5]);
    Selfie::new(substr, |str| &str[3..])
});

assert_eq!("Hello, world!", selfie.owned());
selfie.with_referential(|r| {
    assert_eq!("Hello", r.owned());
    assert_eq!("lo", r.with_referential(|r| *r));
});

依赖