4个版本 (稳定)
1.0.4 | 2024年5月3日 |
---|---|
1.0.3 | 2023年12月20日 |
1.0.2 | 2023年11月10日 |
1.0.1 |
|
0.9.0 |
|
#34 in Rust模式
每月671,568次下载
用于 707 个crate (38直接)
44KB
377 行
self_cell!
使用宏规则宏:self_cell!
在稳定Rust中创建安全使用的自我引用结构体,而不会泄露结构体的内部生命周期。
总的来说,API看起来大致如下
// User code:
self_cell!(
struct NewStructName {
owner: Owner,
#[covariant]
dependent: Dependent,
}
impl {Debug}
);
// Generated by macro:
struct NewStructName(...);
impl NewStructName {
fn new(
owner: Owner,
dependent_builder: impl for<'a> FnOnce(&'a Owner) -> Dependent<'a>
) -> NewStructName { ... }
fn borrow_owner<'a>(&'a self) -> &'a Owner { ... }
fn borrow_dependent<'a>(&'a self) -> &'a Dependent<'a> { ... }
[...]
// See the macro level documentation for a list of all generated functions
// https://docs.rs/self_cell/latest/self_cell/macro.self_cell.html#generated-api.
}
impl Debug for NewStructName { ... }
目前,在安全Rust中不支持使用自我引用结构体。唯一合理的替代方案是要求用户处理两个独立的数据结构,这会很混乱。由于使用了进程宏,库解决方案ouroboros的编译成本非常高。
此替代方案是 no_std
,不使用进程宏,一些自我包含的不安全代码,且在稳定Rust上运行,并通过miri测试。该crate包含不到300行实现代码,主要由类型和特性行为实现,旨在为自我引用结构体的问题提供一个良好的最小解决方案。
它已经经过了 经验丰富的Rust用户的社区代码审查。
快速编译时间
$ rm -rf target && cargo +nightly build -Z timings
Compiling self_cell v0.9.0
Completed self_cell v0.9.0 in 0.2s
因为它不使用进程宏,且没有依赖项,所以编译时间很快。
在慢速笔记本电脑上进行的测量。
一个有说服力的用例
use self_cell::self_cell;
#[derive(Debug, Eq, PartialEq)]
struct Ast<'a>(pub Vec<&'a str>);
self_cell!(
struct AstCell {
owner: String,
#[covariant]
dependent: Ast,
}
impl {Debug, Eq, PartialEq}
);
fn build_ast_cell(code: &str) -> AstCell {
// Create owning String on stack.
let pre_processed_code = code.trim().to_string();
// Move String into AstCell, then build Ast inplace.
AstCell::new(
pre_processed_code,
|code| Ast(code.split(' ').filter(|word| word.len() > 1).collect())
)
}
fn main() {
let ast_cell = build_ast_cell("fox = cat + dog");
println!("ast_cell -> {:?}", &ast_cell);
println!("ast_cell.borrow_owner() -> {:?}", ast_cell.borrow_owner());
println!("ast_cell.borrow_dependent().0[1] -> {:?}", ast_cell.borrow_dependent().0[1]);
}
$ cargo run
ast_cell -> AstCell { owner: "fox = cat + dog", dependent: Ast(["fox", "cat", "dog"]) }
ast_cell.borrow_owner() -> "fox = cat + dog"
ast_cell.borrow_dependent().0[1] -> "cat"
在安全Rust中无法有像 build_ast_cell
这样的API,因为一旦 Ast
依赖于像 pre_processed_code
这样的栈变量,你就不能再从函数中返回值了。你可以将预处理移动到调用者那里,但这会很快变得丑陋,因为你不能再封装东西了。注意,这是一个相当狭窄的用例,自我引用结构体仅应在没有更好的替代方案时使用。
在底层,它堆分配了一个结构体,首先通过将所有者值移动到它中来初始化它,然后使用对这个现在Pin/Immovable所有者的引用来构建依赖的结构体。这使得生成的SelfCell可以安全地移动,但你必须为堆分配付费。
有关更深入的API概述和高级示例,请参阅文档:https://docs.rs/self_cell
安装
运行测试
cargo test
cargo miri test
相关项目
- ouroboros
- rental | 存在性问题(与最近的miri版本一起测试失败)和 已弃用
- Schroedinger | 存在性问题
- owning_ref | 存在性问题 和 似乎未维护
- ghost-cell
- qcell
- selfref
最低要求的 rustc 版本
默认情况下,最低要求的 rustc 版本是 1.51。
有一个可选功能可以启用,称为 "old_rust",它支持 down 到 rustc 版本 1.36。然而,这需要使用技术上 UB 的版本来填充旧 rustc 的 std 库功能。测试没有显示旧 rustc 版本(ab)使用此功能。请自行承担风险。
最低版本是尽力而为的,并可能随着任何新的主要版本而更改。
贡献
在贡献时,请尊重 CODE_OF_CONDUCT.md。
版本控制
我们使用 SemVer 进行版本控制。有关可用版本,请参阅 此存储库的标签。
作者
- Lukas Bergdoll - 初始工作 - Voultapher
有关参与此项目的 贡献者列表,也请参阅。
许可
本项目采用 Apache License,版本 2.0 - 请参阅 LICENSE.md 文件以获取详细信息。