1 个不稳定版本
0.0.3 | 2024年4月30日 |
---|---|
0.0.2 |
|
0.0.1 |
|
#330 在 Rust 模式
每月191 次下载
46KB
377 行
自拍
一个轻量级自引用结构体库。无宏、无分配,且支持 #![no_std]
。
该包是实验性的,尚未准备好用于生产使用!
该包是一个实验,旨在创建简单且无分配的自引用结构体,这在实时音频环境中是必需的。
虽然这个库很小,并在 MIRI 下进行了广泛的测试,我相信它是安全的,但它尚未经过同行评审或得到足够的实际应用。
如果您愿意尝试它,请随时!欢迎对稳定性、可用性进行审查和提交 PR:自引用结构体是一个复杂的问题,我唯一有信心的地方是库的名称。
优势
已经存在其他自引用结构体库,但它们并不完全符合我的需求
- 无宏:
Selfie
不会使用 proc-macros 或宏来创建自引用结构体。这允许快速编译时间,同时也有简单、IDE 友好的语法,不会干扰更复杂的场景。 - 无分配:创建
Selfie
不会执行任何分配,实际上是一个零成本操作。Selfie
结构体将拥有的指针和引用类型存储在彼此旁边,因此唯一的间接引用就是从已经存在的 owned 指针。这也意味着Selfie
库完全是#![no_std]
。 - 对于拥有的类型几乎没有限制:拥有的类型的唯一要求是它位于一个可固定和稳定的指针后面(即实现
StableDeref
)。标准库中的候选包括&T
、&mut T
、Box
、Rc
、Arc
、String
、Vec
以及其他,但任何外部库(如 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));
});