#tags #static #thread-safe #lazy-evaluation #macro #zst

tagged_cell

快速、可初始化和线程安全的静态变量

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 模式

MIT/Apache

8KB
68

tagged_cell

CI Crates.io API reference

快速、可初始化和线程安全的静态变量

借用基于 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);
});

无运行时依赖