1 个不稳定版本
0.1.0 | 2022年12月8日 |
---|
#689 在 并发
53KB
718 行
cell-family
受 qcell::TCell
/ qcell::TLCell
启发,具有额外功能。
概述
cell-family
提供了 define!
宏,用于定义一个新的 Family
。对于每个家族,可以创建相应的 Cell
和 CellOwner
。每个家族只能存在一个 CellOwner
,但可以同时存在多个单元格。
例如,您可能如下定义一个家族 FooFamily
cell_family::define!(type FooFamily: FooCellOwner for FooCell<T>);
这定义了 FooFamily
(实现了 Family
)以及 FooCellOwner
和 FooCell
,分别是 CellOwner<FooFamily>
和 Cell<FooFamily>
的别称。
每个线程可以存在一个 FooCellOwner
,因此 FooCellOwner
是 不 Send
,因为将 FooCellOwner
发送到另一个线程可能会允许在单个线程中存在两个 FooCellOwner
。要允许每个程序存在一个 FooCellOwner
(并使 FooCellOwner
成为 Send
),请在 define!
前面加上 static
cell_family::define!(static type FooFamily: FooCellOwner for FooCell<T>);
对于线程局部和线程安全的家族,API 是相同的
let mut owner = FooCellOwner::new();
let a = FooCell::new(1);
let b = FooCell::new("bar");
assert_eq!(*a.get(&owner), 1);
assert_eq!(*b.get(&owner), "bar");
*a.get_mut(&mut owner) += 1;
*b.get_mut(&mut owner) = "baz";
assert_eq!(*a.get(&owner), 2);
assert_eq!(*b.get(&owner), "baz");
FooCell::new(T)
简单地将T
包装在#[repr(transparent)]
FooCell
中,而不执行任何检查。FooCell::get(&FooCellOwner)
和FooCell::get_mut(&mut FooCellOwner)
是常数时间操作,分别返回&T
和&mut T
而不执行任何运行时检查。由于每个程序(或线程)只有一个FooCellOwner
存在,Rust 通过FooCellOwner
强制执行每个单元的别名规则,只要每个FooCell
被借用,FooCellOwner
就会被借用。FooFamily
确保程序中存在单个FooCellOwner
;如果存在另一个FooCellOwner
,FooCellOwner::new()
将会引发 panic。为了避免这种情况崩溃,存在一个try_new()
对应方法。
相对于 qcell::TCell
/ qcell::TLCell
的优势
-
与
qcell::TCell
(分别qcell::TCell
)不同,Family
F
负责确保程序(分别线程)中存在单个CellOwner<F>
。通过使用宏来生成家族,我们只需要为每个家族提供一个AtomicBool
(分别Cell<bool>
),因此不需要分配。 -
提供了一些额外的方法;例如,
owner.get(c)
,owner.get_mut(c)
和owner.try_get_mut(c)
,其中c
可以是 -
线程局部和线程安全的
Cell
(以及CellOwner
)由相同类型支持;它们是线程局部还是线程安全由它们的Family
决定:如果是线程安全的,它也将实现ThreadSafeFamily
。这使得在Cell
上定义泛型函数更加容易。 -
cell-family
完全支持#[no_std]
,但不包括非nightly
构建中的线程局部家族(因为在不使用#[thread_local]
的情况下无法在#[no_std]
中定义线程局部变量,这还不稳定)。 -
Cell
实现Debug
,如果当前不存在CellOwner
,将打印其内部值的表示。