token_cell/
macros.rs

1/// Produces tokens that are also checked at runtime, ensuring that a [`TokenCell`](crate::core::TokenCell) is never accidentally used with another instance of the same token type.
2#[macro_export]
3macro_rules! runtime_token {
4($vis: vis $id: ident) => {
5    $crate::paste! {
6        $vis use [<__ $id _mod__ >]::$id;
7        #[allow(nonstandard_style)]
8        mod [<__ $id _mod__ >] {
9            use $crate::core::TokenCell;
10            use core::{convert::Infallible, sync::atomic::AtomicU16};
11            static COUNTER: AtomicU16 = AtomicU16::new(0);
12            /// A small token that's also checked at runtime, ensuring that a [`TokenCell`] is never accidentally used with another instance of the same token type.
13            pub struct $id(u16);
14            impl $crate::core::TokenTrait for $id {
15                type ConstructionError = Infallible;
16                type RunError = Infallible;
17                type Identifier = u16;
18                type ComparisonError = $crate::macros::IdMismatch;
19                type Branded<'a> = Self;
20                fn new() -> Result<Self, Self::ConstructionError> {
21                    Ok($id(
22                        COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed),
23                    ))
24                }
25                fn with_token<R, F: FnOnce(Self)->R>(f: F) -> Result<R, Self::RunError> {
26                    Self::new().map(f)
27                }
28                fn identifier(&self) -> Self::Identifier {
29                    self.0
30                }
31                fn compare(&self, id: &Self::Identifier) -> Result<(), Self::ComparisonError> {
32                    if self.0 == *id {
33                        Ok(())
34                    } else {
35                        Err($crate::macros::IdMismatch {
36                            cell: *id,
37                            token: self.0,
38                        })
39                    }
40                }
41            }
42        }
43    }
44};
45($($vis: vis $id: ident),*) => {
46    $($crate::runtime_token!($vis $id);)*
47}
48}
49
50/// Produces tokens whose only identifier is their type, but is built such that only one instance of it can exist at any given time.
51///
52/// Looping on [`TokenTrait::new`](crate::core::TokenTrait::new) with a singleton token to access a [`TokenCell`](crate::core::TokenCell) is equivalent to using a spin-lock.
53#[macro_export]
54macro_rules! singleton_token {
55($vis: vis $id: ident) => {
56    $crate::paste! {
57        $vis use [<__ $id _mod__ >]::$id;
58        #[allow(nonstandard_style)]
59        mod [<__ $id _mod__ >] {
60            use core::{convert::Infallible, sync::atomic::AtomicBool};
61            use $crate::SingletonUnavailable;
62            static AVAILABLE: AtomicBool = AtomicBool::new(true);
63            /// A ZST tokens whose only identifier is their type, but is built such that only one instance of it can exist at any given time.
64            ///
65            /// Looping on [`TokenTrait::new`](token_cell::core::TokenTrait::new) with this type to access a [`TokenCell`](token_cell::core::TokenCell) is equivalent to using a spin-lock.
66            pub struct $id(());
67            impl $crate::core::TokenTrait for $id {
68                type ConstructionError = SingletonUnavailable;
69                type RunError = SingletonUnavailable;
70                type Identifier = ();
71                type ComparisonError = Infallible;
72                fn new() -> Result<Self, Self::ConstructionError> {
73                    if AVAILABLE.swap(false, core::sync::atomic::Ordering::Relaxed) {
74                        Ok($id(()))
75                    } else {
76                        Err(SingletonUnavailable)
77                    }
78                }
79                fn with_token<R, F: FnOnce(Self)->R>(f: F) -> Result<R, Self::RunError> {
80                    Self::new().map(f)
81                }
82                fn identifier(&self) -> Self::Identifier {
83                    self.0
84                }
85                fn compare(&self, _: &Self::Identifier) -> Result<(), Self::ComparisonError> {
86                    Ok(())
87                }
88            }
89            impl ::core::ops::Drop for $id {
90                fn drop(&mut self) {
91                    AVAILABLE.store(true, core::sync::atomic::Ordering::Relaxed);
92                }
93            }
94        }
95    }
96};
97($($vis: vis $id: ident),*) => {
98    $($crate::singleton_token!($vis $id);)*
99}
100}
101
102/// Produces tokens whose only identifier is their type.
103///
104/// While unlikely, a potential misuse is constructing multiple instances of the same type and using one to access a cell constructed by another instance.
105///
106/// For example, if you have multiple instances of a tree that uses a single mutex to lock all of its `Arc`-ed nodes through a token built with [`unsafe_token`](crate::unsafe_token), one's token could unlock another's node without causing any errors.
107#[macro_export]
108macro_rules! unsafe_token {
109($vis: vis $id: ident) => {
110    $crate::paste! {
111        $vis use [<__ $id _mod__ >]::$id;
112        #[allow(nonstandard_style)]
113        mod [<__ $id _mod__ >] {
114            use core::convert::Infallible;
115            /// A ZST token whose only identifier is its type.
116            ///
117            /// While unlikely, a potential misuse is constructing multiple instances of the same type and using one to access a cell constructed by another instance.
118            ///
119            /// For example, if you have multiple instances of a tree that uses a single mutex to lock all of its [`Arc`](alloc::sync::Arc)-ed nodes through a token built with this type.
120            pub struct $id(());
121            impl $crate::core::TokenTrait for $id {
122                type ConstructionError = Infallible;
123                type RunError = Infallible;
124                type Identifier = ();
125                type ComparisonError = Infallible;
126                type Branded<'a> = Self;
127                fn new() -> Result<Self, Self::ConstructionError> {
128                    Ok($id(()))
129                }
130                fn with_token<R, F: FnOnce(Self)->R>(f: F) -> Result<R, Self::RunError> {
131                    Self::new().map(f)
132                }
133                fn identifier(&self) -> Self::Identifier {
134                    self.0
135                }
136                fn compare(&self, _: &Self::Identifier) -> Result<(), Self::ComparisonError> {
137                    Ok(())
138                }
139            }
140        }
141    }
142};
143($($vis: vis $id: ident),*) => {
144    $($crate::unsafe_token!($vis $id);)*
145}
146}
147pub use token::token;
148#[cfg(any(feature = "debug", debug_assertions))]
149mod token {
150    pub use crate::runtime_token as token;
151}
152#[cfg(not(any(feature = "debug", debug_assertions)))]
153mod token {
154    pub use crate::unsafe_token as token;
155}
156
157/// The comparison error for runtime tokens.
158#[derive(Debug, Clone, Copy)]
159pub struct IdMismatch {
160    /// The identifier of the token the cell was expecting.
161    pub cell: u16,
162    /// The identifier of the token that was used to attempt accessing the cell's contents.
163    pub token: u16,
164}
165impl ::core::fmt::Display for IdMismatch {
166    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
167        write!(f, "{:?}", self)
168    }
169}
170/// The construction error for [`singleton_token`]s.
171#[derive(Debug, Clone, Copy)]
172pub struct SingletonUnavailable;
173impl ::core::fmt::Display for SingletonUnavailable {
174    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
175        write!(f, "{:?}", self)
176    }
177}