4 个版本
0.1.3 | 2022 年 3 月 16 日 |
---|---|
0.1.2 | 2022 年 3 月 13 日 |
0.1.1 | 2021 年 9 月 12 日 |
0.1.0 | 2021 年 9 月 12 日 |
#2713 in Rust 模式
8KB
68 行
tagged_cell
快速、可初始化和线程安全的静态变量
借用基于 ZST 的优秀标记实现,以确保在尝试访问之前,单元格被精确初始化一次。
这是通过 [TaggedCell] 和一个 Tag 类型实现的,该类型对于每个 [TaggedCell] 实例必须是唯一的,以确保安全操作。然后通过 init() 来设置 [TaggedCell],该函数使用用户提供的函数或闭包初始化底层数据,然后返回一个用于访问单元格数据的特殊零大小 [Init] 标记。
use tagged_cell::TaggedCell;
struct FooTag;
static FOO: TaggedCell<usize, FooTag> = unsafe {TaggedCell::new()};
// Initialize the cell's data and retrieve a tag
let tag = FOO.init(|| 27);
// The tag is required to obtain a shared reference to the data
assert_eq!(*FOO.get(tag), 27);
为了确保每个单元格使用唯一的标记类型,并“包装”不安全的调用,提供了一个 [tagged_cell!] 宏。该宏基于变量的名称创建一个新的标记类型,并将其应用于声明。
use tagged_cell::tagged_cell;
tagged_cell!{
static BAR: TaggedCell<Vec<usize>, _> = TaggedCell::new();
}
let tag = BAR.init(|| vec![0, 10, 20]);
let vec = BAR.get(tag);
assert_eq!(vec[2], 20);
当使用唯一的标记类型时,在初始化之前尝试访问 [TaggedCell] 会导致编译错误。
use tagged_cell::tagged_cell;
tagged_cell!{
static BAZ: TaggedCell<usize>, _> = TaggedCell::new();
}
tagged_cell!{
static QUX: TaggedCell<usize>, _> = TaggedCell::new();
}
// read before init is not possible
BAZ.get(Init{BAZ::TagType});
let qux_tag = QUX.init(|| 35);
// using the wrong tag throws an error
BAZ.get(qux_tag);
为了允许跨线程使用,只有 init() 的第一次调用将初始化单元格的数据。所有未来的 init() 调用将只返回一个新的标记。哪个线程将初始化单元格的数据是不确定的。
use std::thread;
use tagged_cell::tagged_cell;
tagged_cell!{
static TABLE: TaggedCell<Vec<usize>, _> = TaggedCell::new();
}
thread::spawn(move || {
let tag = TABLE.init(|| vec![0, 10, 20]);
let table = TABLE.get(tag);
assert_eq!(table[2], 20);
});
thread::spawn(move || {
let tag = TABLE.init(|| vec![0, 10, 20]);
let table = TABLE.get(tag);
assert_eq!(table[1], 10);
});