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