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