#family #cell #define #owner #thread #unique #send

no-std cell-family

通过唯一的拥有者访问的低成本单元格

1 个不稳定版本

0.1.0 2022年12月8日

#689并发

ISC 许可证

53KB
718

cell-family

qcell::TCell / qcell::TLCell 启发,具有额外功能。

概述

cell-family 提供了 define! 宏,用于定义一个新的 Family。对于每个家族,可以创建相应的 CellCellOwner。每个家族只能存在一个 CellOwner,但可以同时存在多个单元格。

例如,您可能如下定义一个家族 FooFamily

cell_family::define!(type FooFamily: FooCellOwner for FooCell<T>);

这定义了 FooFamily(实现了 Family)以及 FooCellOwnerFooCell,分别是 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;如果存在另一个 FooCellOwnerFooCellOwner::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,将打印其内部值的表示。

依赖关系