token_cell/
macros.rs

1#[macro_export]
2macro_rules! runtime_token {
3($vis: vis $id: ident) => {
4    $crate::paste! {
5        $vis use [<__ $id _mod__ >]::$id;
6        #[allow(nonstandard_style)]
7        mod [<__ $id _mod__ >] {
8            use core::{convert::Infallible, sync::atomic::AtomicU16};
9            static COUNTER: AtomicU16 = AtomicU16::new(0);
10            pub struct $id(u16);
11            impl $crate::core::TokenTrait for $id {
12                type ConstructionError = Infallible;
13                type RunError = Infallible;
14                type Identifier = u16;
15                type ComparisonError = $crate::macros::IdMismatch;
16                fn new() -> Result<Self, Self::ConstructionError> {
17                    Ok($id(
18                        COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed),
19                    ))
20                }
21                fn with_token<R, F: FnOnce(Self)->R>(f: F) -> Result<R, Self::RunError> {
22                    Self::new().map(f)
23                }
24                fn identifier(&self) -> Self::Identifier {
25                    self.0
26                }
27                fn compare(&self, id: &Self::Identifier) -> Result<(), Self::ComparisonError> {
28                    if self.0 == *id {
29                        Ok(())
30                    } else {
31                        Err($crate::macros::IdMismatch {
32                            cell: *id,
33                            token: self.0,
34                        })
35                    }
36                }
37            }
38        }
39    }
40};
41($($vis: vis $id: ident),*) => {
42    $($crate::runtime_token!($vis $id);)*
43}
44}
45
46#[macro_export]
47macro_rules! singleton_token {
48($vis: vis $id: ident) => {
49    $crate::paste! {
50        $vis use [<__ $id _mod__ >]::$id;
51        #[allow(nonstandard_style)]
52        mod [<__ $id _mod__ >] {
53            use core::{convert::Infallible, sync::atomic::AtomicBool};
54            use $crate::SingletonUnavailable;
55            static AVAILABLE: AtomicBool = AtomicBool::new(true);
56            pub struct $id(());
57            impl $crate::core::TokenTrait for $id {
58                type ConstructionError = SingletonUnavailable;
59                type RunError = SingletonUnavailable;
60                type Identifier = ();
61                type ComparisonError = Infallible;
62                fn new() -> Result<Self, Self::ConstructionError> {
63                    if AVAILABLE.swap(false, core::sync::atomic::Ordering::Relaxed) {
64                        Ok($id(()))
65                    } else {
66                        Err(SingletonUnavailable)
67                    }
68                }
69                fn with_token<R, F: FnOnce(Self)->R>(f: F) -> Result<R, Self::RunError> {
70                    Self::new().map(f)
71                }
72                fn identifier(&self) -> Self::Identifier {
73                    self.0
74                }
75                fn compare(&self, _: &Self::Identifier) -> Result<(), Self::ComparisonError> {
76                    Ok(())
77                }
78            }
79            impl ::core::ops::Drop for $id {
80                fn drop(&mut self) {
81                    AVAILABLE.store(true, core::sync::atomic::Ordering::Relaxed);
82                }
83            }
84        }
85    }
86};
87($($vis: vis $id: ident),*) => {
88    $($crate::singleton_token!($vis $id);)*
89}
90}
91
92#[macro_export]
93macro_rules! unsafe_token {
94($vis: vis $id: ident) => {
95    $crate::paste! {
96        $vis use [<__ $id _mod__ >]::$id;
97        #[allow(nonstandard_style)]
98        mod [<__ $id _mod__ >] {
99            use core::convert::Infallible;
100            pub struct $id(());
101            impl $crate::core::TokenTrait for $id {
102                type ConstructionError = Infallible;
103                type RunError = Infallible;
104                type Identifier = ();
105                type ComparisonError = Infallible;
106                fn new() -> Result<Self, Self::ConstructionError> {
107                    Ok($id(()))
108                }
109                fn with_token<R, F: FnOnce(Self)->R>(f: F) -> Result<R, Self::RunError> {
110                    Self::new().map(f)
111                }
112                fn identifier(&self) -> Self::Identifier {
113                    self.0
114                }
115                fn compare(&self, _: &Self::Identifier) -> Result<(), Self::ComparisonError> {
116                    Ok(())
117                }
118            }
119        }
120    }
121};
122($($vis: vis $id: ident),*) => {
123    $($crate::unsafe_token!($vis $id);)*
124}
125}
126pub use token::token;
127#[cfg(any(feature = "debug", debug_assertions))]
128mod token {
129    pub use crate::runtime_token as token;
130}
131#[cfg(not(any(feature = "debug", debug_assertions)))]
132mod token {
133    pub use crate::unsafe_token as token;
134}
135
136#[derive(Debug, Clone, Copy)]
137pub struct IdMismatch {
138    pub cell: u16,
139    pub token: u16,
140}
141impl ::core::fmt::Display for IdMismatch {
142    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
143        write!(f, "{:?}", self)
144    }
145}
146#[derive(Debug, Clone, Copy)]
147pub struct SingletonUnavailable;
148impl ::core::fmt::Display for SingletonUnavailable {
149    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
150        write!(f, "{:?}", self)
151    }
152}