Skip to main content

token_cell/
macros.rs

1/// Produces tokens whose only identifier is their type, but is built such that only one instance of it can exist at any given time.
2///
3/// 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.
4///
5/// Note that you're almost always better off placing an [`unsafe_token`] inside a `Mutex` instead if you expect contention on the token.
6#[macro_export]
7macro_rules! singleton_token {
8($(#[$meta: meta])* $vis: vis $id: ident) => {
9    $crate::paste! {
10        $vis use [<__ $id _mod__ >]::$id;
11        #[allow(nonstandard_style)]
12        mod [<__ $id _mod__ >] {
13            use core::{convert::Infallible, sync::atomic::AtomicBool};
14            use $crate::SingletonUnavailable;
15            static AVAILABLE: AtomicBool = AtomicBool::new(true);
16
17            $(#[$meta])*
18            pub struct $id(());
19            impl $crate::core::UnscopedToken for $id {
20                type ConstructionError = SingletonUnavailable;
21                fn try_new() -> Result<Self, Self::ConstructionError> {
22                    if AVAILABLE.swap(false, core::sync::atomic::Ordering::Relaxed) {
23                        Ok($id(()))
24                    } else {
25                        Err(SingletonUnavailable)
26                    }
27                }
28            }
29            impl ::core::ops::Drop for $id {
30                fn drop(&mut self) {
31                    AVAILABLE.store(true, core::sync::atomic::Ordering::Relaxed);
32                }
33            }
34            impl $crate::core::TokenTrait for $id {
35                type ComparisonMaySpuriouslyEq = $crate::core::False;
36                type RunError = SingletonUnavailable;
37                type Identifier = ();
38                type ComparisonError = Infallible;
39                fn with_token<R, F: FnOnce(Self)->R>(f: F) -> Result<R, Self::RunError> {
40                    Self::try_new().map(f)
41                }
42                fn identifier(&self) -> Self::Identifier {
43                    self.0
44                }
45                fn compare(&self, _: &Self::Identifier) -> Result<(), Self::ComparisonError> {
46                    Ok(())
47                }
48            }
49            impl ::core::ops::Drop for $id {
50                fn drop(&mut self) {
51                    AVAILABLE.store(true, core::sync::atomic::Ordering::Relaxed);
52                }
53            }
54        }
55    }
56};
57($($(#[$meta: meta])* $vis: vis $id: ident),*) => {
58    $($crate::singleton_token!($(#[$meta])* $vis $id);)*
59}
60}
61
62/// Produces tokens whose only identifier is their type.
63///
64/// While unlikely, a potential misuse is constructing multiple instances of the same type and using one to access a cell constructed by another instance.
65///
66/// 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.
67#[macro_export]
68macro_rules! unsafe_token {
69($(#[$meta: meta])* $vis: vis $id: ident) => {
70    $crate::paste! {
71        $vis use [<__ $id _mod__ >]::$id;
72        #[allow(nonstandard_style)]
73        mod [<__ $id _mod__ >] {
74            use core::convert::Infallible;
75            use $crate::core::UnscopedToken;
76
77            $(#[$meta])*
78            pub struct $id(());
79            impl UnscopedToken for $id {
80                type ConstructionError = Infallible;
81                fn try_new() -> Result<Self, Self::ConstructionError> {
82                    Ok(Self(()))
83                }
84            }
85            impl $crate::core::TokenTrait for $id {
86                type ComparisonMaySpuriouslyEq = $crate::core::True;
87                type RunError = Infallible;
88                type Identifier = ();
89                type ComparisonError = Infallible;
90                type Branded<'a> = Self;
91                fn with_token<R, F: FnOnce(Self)->R>(f: F) -> Result<R, Self::RunError> {
92                    Ok(f(Self::new()))
93                }
94                fn identifier(&self) -> Self::Identifier {
95                    self.0
96                }
97                fn compare(&self, _: &Self::Identifier) -> Result<(), Self::ComparisonError> {
98                    Ok(())
99                }
100            }
101        }
102    }
103};
104($($(#[$meta: meta])* $vis: vis $id: ident),*) => {
105    $($crate::unsafe_token!($(#[$meta])* $vis $id);)*
106}
107}
108pub use token::token;
109#[cfg(any(feature = "debug", debug_assertions))]
110mod token {
111    pub use crate::runtime_token as token;
112}
113#[cfg(not(any(feature = "debug", debug_assertions)))]
114mod token {
115    pub use crate::unsafe_token as token;
116}
117
118/// The construction error for [`singleton_token`]s.
119#[derive(Debug, Clone, Copy)]
120pub struct SingletonUnavailable;
121impl ::core::fmt::Display for SingletonUnavailable {
122    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
123        write!(f, "{:?}", self)
124    }
125}