1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use core::{convert::Infallible, sync::atomic::AtomicUsize};
pub trait TokenTrait: Sized {
type Checker: TokenChecker<Self>;
}
pub trait TokenChecker<Token> {
type Input;
type Error;
fn check(&self, token: &Token) -> Result<(), Self::Error>;
fn new(input: Self::Input) -> Self;
fn from_ref(token: &Token) -> Self;
}
#[macro_export]
macro_rules! generate_static_token {
($vis: vis $id: ident) => {
$vis struct $id(token_cell::support::NoopChecker);
impl $id {
pub fn new() -> Self {
unsafe {$id(token_cell::support::NoopChecker::new())}
}
}
impl token_cell::support::TokenTrait for $id {
type Checker = token_cell::support::NoopChecker;
}
};
($($vis:vis $id: ident),+) => {
$(token_cell::generate_static_token!($vis $id);)*
};
}
#[derive(Clone, Copy)]
pub struct NoopChecker(());
impl NoopChecker {
pub unsafe fn new() -> Self {
NoopChecker(())
}
}
impl<T> TokenChecker<T> for NoopChecker {
type Error = Infallible;
type Input = ();
fn check(&self, _: &T) -> Result<(), Self::Error> {
Ok(())
}
fn new(_: ()) -> Self {
unsafe { NoopChecker::new() }
}
fn from_ref(_: &T) -> Self {
unsafe { NoopChecker::new() }
}
}
static UID: AtomicUsize = AtomicUsize::new(0);
pub struct RuntimeToken {
id: usize,
}
impl RuntimeToken {
pub fn new() -> Self {
RuntimeToken {
id: UID.fetch_add(1, core::sync::atomic::Ordering::Relaxed),
}
}
}
impl Default for RuntimeToken {
fn default() -> Self {
Self::new()
}
}
impl TokenTrait for RuntimeToken {
type Checker = Self;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IdMismatch;
impl core::fmt::Display for IdMismatch {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("IdMismatch")
}
}
impl TokenChecker<RuntimeToken> for RuntimeToken {
type Error = IdMismatch;
type Input = *const RuntimeToken;
fn check(&self, token: &RuntimeToken) -> Result<(), Self::Error> {
match self.id == token.id {
true => Ok(()),
false => Err(IdMismatch),
}
}
fn new(input: Self::Input) -> Self {
unsafe { RuntimeToken { id: (*input).id } }
}
fn from_ref(token: &RuntimeToken) -> Self {
RuntimeToken { id: token.id }
}
}