token_cell/
core.rs

1use ::core::{
2    cell::UnsafeCell,
3    ops::{Deref, DerefMut},
4};
5
6trait MapLikely<T> {
7    type Output<U>;
8    fn map_likely<U, F: FnOnce(T) -> U>(self, f: F) -> Self::Output<U>;
9}
10#[cold]
11const fn cold() {}
12impl<T, E> MapLikely<T> for Result<T, E> {
13    type Output<U> = Result<U, E>;
14    fn map_likely<U, F: FnOnce(T) -> U>(self, f: F) -> Self::Output<U> {
15        match self {
16            Ok(v) => Ok(f(v)),
17            Err(e) => {
18                cold();
19                Err(e)
20            }
21        }
22    }
23}
24
25use crate::monads::{TokenMap, TokenMapMut};
26/// A trait for tokens
27pub trait TokenTrait: Sized {
28    /// Constructing a token may fail.
29    type ConstructionError;
30    /// [`TokenTrait::with_token`] may fail, typically if construction failed.
31    ///
32    /// Some types, like [`GhostToken`](crate::ghost::GhostToken) are inconstructible with [`TokenTrait::new`], but cannot fail to run, hence the distinction.
33    type RunError;
34    /// Lets a [`TokenCell`] keep track of the token.
35    ///
36    /// In most cases, this is a ZST in release mode.
37    type Identifier;
38    /// [`core::convert::Infallible`] unless [`TokenTrait::compare`] is fallible (ie. comparison is done at runtime).
39    type ComparisonError;
40    /// Rebrands the token, this is necessary for [`GhostToken`](crate::ghost::GhostToken) to function properly
41    type Branded<'a>;
42    /// Constructs a new Token.
43    ///
44    /// # Errors
45    /// Some token implementations may chose to be constructible only once, or only while holding a given lock.
46    fn new() -> Result<Self, Self::ConstructionError>;
47    /// Constructs a new, lifetime-branded Token, and provides it to the closure.
48    ///
49    /// This is especially useful for [`GhostToken`](crate::ghost::GhostToken), which can only be constructed that way, as they use lifetimes to obtain a unique brand.
50    ///
51    /// # Errors
52    /// If construction failed, so will this.
53    fn with_token<R, F: for<'a> FnOnce(Self::Branded<'a>) -> R>(f: F) -> Result<R, Self::RunError>;
54    /// Returns the Token's identifier, which cells may store to allow comparison.
55    fn identifier(&self) -> Self::Identifier;
56    /// Allows the cell to compare its identifier to the Token.
57    ///
58    /// # Errors
59    /// If a wrong token was mistakenly passed to the cell.
60    fn compare(&self, id: &Self::Identifier) -> Result<(), Self::ComparisonError>;
61}
62
63/// Common ways to interract with a [`TokenCell`].
64///
65/// Note that while many functions document fallihle behaviours, this behaviour is only reachable for tokens that perform runtime check. These are identifiable by their [`TokenTrait::ComparisonError`] type not being [`core::convert::Infallible`].
66pub trait TokenCellTrait<T: ?Sized, Token: TokenTrait>: Sync {
67    /// Constructs a new cell using `token` as its key.
68    fn new(inner: T, token: &Token) -> Self
69    where
70        T: Sized;
71    /// Attempts to construct a guard which [`Deref`]s to the inner data,
72    /// but also allows recovering the `Token`.
73    ///
74    /// # Errors
75    /// If the token provides runtime checking and detects that `self` was constructed with another token.
76    fn try_guard<'l>(
77        &'l self,
78        token: &'l Token,
79    ) -> Result<TokenGuard<'l, T, Token>, Token::ComparisonError>;
80    /// Attempts to borrow the inner data.
81    ///
82    /// # Errors
83    /// If the token provides runtime checking and detects that `self` was constructed with another token.
84    fn try_borrow<'l>(&'l self, token: &'l Token) -> Result<&'l T, Token::ComparisonError>;
85    /// Attempts to construct a guard which [`DerefMut`]s to the inner data,
86    /// but also allows recovering the `Token`.
87    ///
88    /// # Errors
89    /// If the token provides runtime checking and detects that `self` was constructed with another token.
90    fn try_guard_mut<'l>(
91        &'l self,
92        token: &'l mut Token,
93    ) -> Result<TokenGuardMut<'l, T, Token>, Token::ComparisonError>;
94    /// Attempts to borrow the inner data mutably.
95    ///
96    /// # Errors
97    /// If the token provides runtime checking and detects that `self` was constructed with another token.
98    fn try_borrow_mut<'l>(
99        &'l self,
100        token: &'l mut Token,
101    ) -> Result<&'l mut T, Token::ComparisonError>;
102    /// Borrows the inner data, panicking if the wrong token was used as key.
103    fn borrow<'l>(&'l self, token: &'l Token) -> &'l T
104    where
105        Token::ComparisonError: core::fmt::Debug,
106    {
107        self.try_borrow(token).unwrap()
108    }
109    /// Borrows the inner data mutably, panicking if the wrong token was used as key.
110    fn borrow_mut<'l>(&'l self, token: &'l mut Token) -> &'l mut T
111    where
112        Token::ComparisonError: core::fmt::Debug,
113    {
114        self.try_borrow_mut(token).unwrap()
115    }
116    /// Constructs a lazy computation that can then be applied using the token.
117    fn map<'a, U, F: FnOnce(TokenGuard<'a, T, Token>) -> U>(
118        &'a self,
119        f: F,
120    ) -> TokenMap<'a, T, U, F, Self, Token> {
121        TokenMap {
122            cell: self,
123            f,
124            marker: core::marker::PhantomData,
125        }
126    }
127    /// Constructs a lazy computation that can then be applied using the token.
128    fn map_mut<'a, U, F: FnOnce(TokenGuardMut<'a, T, Token>) -> U>(
129        &'a self,
130        f: F,
131    ) -> TokenMapMut<'a, T, U, F, Self, Token> {
132        TokenMapMut {
133            cell: self,
134            f,
135            marker: core::marker::PhantomData,
136        }
137    }
138}
139
140/// A guard that allows immutably borrowing the cell's value, as well as its token.
141pub struct TokenGuard<'a, T: ?Sized, Token: TokenTrait> {
142    cell: &'a TokenCell<T, Token>,
143    token: &'a Token,
144}
145impl<'a, T: ?Sized, Token: TokenTrait> TokenGuard<'a, T, Token> {
146    /// Reborrows the token immutably.
147    pub const fn token(&self) -> &Token {
148        self.token
149    }
150}
151impl<'a, T: ?Sized, Token: TokenTrait> Deref for TokenGuard<'a, T, Token> {
152    type Target = T;
153    fn deref(&self) -> &Self::Target {
154        unsafe { &*self.cell.inner.get() }
155    }
156}
157
158/// A guard that allows mutably borrowing the cell's value, as well as its token.
159pub struct TokenGuardMut<'a, T: ?Sized, Token: TokenTrait> {
160    cell: &'a TokenCell<T, Token>,
161    token: &'a mut Token,
162}
163impl<'a, T: ?Sized, Token: TokenTrait> TokenGuardMut<'a, T, Token> {
164    /// Reborrows the token immutably.
165    pub fn token(&self) -> &Token {
166        self.token
167    }
168    /// Reborrows the token mutably.
169    pub fn token_mut(&mut self) -> &mut Token {
170        self.token
171    }
172}
173impl<'a, T: ?Sized, Token: TokenTrait> Deref for TokenGuardMut<'a, T, Token> {
174    type Target = T;
175    fn deref(&self) -> &Self::Target {
176        unsafe { &*self.cell.inner.get() }
177    }
178}
179impl<'a, T, Token: TokenTrait> core::ops::DerefMut for TokenGuardMut<'a, T, Token> {
180    fn deref_mut(&mut self) -> &mut Self::Target {
181        unsafe { &mut *self.cell.inner.get() }
182    }
183}
184
185/// A Cell that shifts the management of access permissions to its inner value onto a `Token`.
186pub struct TokenCell<T: ?Sized, Token: TokenTrait> {
187    token_id: Token::Identifier,
188    inner: UnsafeCell<T>,
189}
190impl<T: ?Sized, Token: TokenTrait> TokenCell<T, Token> {
191    /// While cells are typically behind immutable references,
192    /// obtaining a mutable reference to one is still proof of unique access.
193    pub fn get_mut(&mut self) -> &mut T {
194        self.inner.get_mut()
195    }
196}
197impl<T: Sized, Token: TokenTrait> TokenCell<T, Token> {
198    /// Unwraps the value from the cell.
199    ///
200    /// Full ownership of the cell is sufficient proof that the inner value can be recovered.
201    pub fn into_inner(self) -> T {
202        self.inner.into_inner()
203    }
204}
205impl<T: ?Sized, Token: TokenTrait> Deref for TokenCell<T, Token> {
206    type Target = UnsafeCell<T>;
207    fn deref(&self) -> &Self::Target {
208        &self.inner
209    }
210}
211impl<T: ?Sized, Token: TokenTrait> DerefMut for TokenCell<T, Token> {
212    fn deref_mut(&mut self) -> &mut Self::Target {
213        &mut self.inner
214    }
215}
216
217unsafe impl<T: ?Sized, Token: TokenTrait> Sync for TokenCell<T, Token> {}
218
219impl<T: ?Sized, Token: TokenTrait> TokenCellTrait<T, Token> for TokenCell<T, Token> {
220    fn new(inner: T, token: &Token) -> Self
221    where
222        T: Sized,
223    {
224        TokenCell {
225            inner: UnsafeCell::new(inner),
226            token_id: token.identifier(),
227        }
228    }
229    fn try_guard<'l>(
230        &'l self,
231        token: &'l Token,
232    ) -> Result<TokenGuard<'l, T, Token>, <Token as TokenTrait>::ComparisonError> {
233        token
234            .compare(&self.token_id)
235            .map_likely(move |_| TokenGuard { cell: self, token })
236    }
237    fn try_borrow<'l>(&'l self, token: &'l Token) -> Result<&'l T, Token::ComparisonError> {
238        token
239            .compare(&self.token_id)
240            .map_likely(move |_| unsafe { &*self.inner.get() })
241    }
242    fn try_guard_mut<'l>(
243        &'l self,
244        token: &'l mut Token,
245    ) -> Result<TokenGuardMut<'l, T, Token>, <Token as TokenTrait>::ComparisonError> {
246        token
247            .compare(&self.token_id)
248            .map_likely(move |_| TokenGuardMut { cell: self, token })
249    }
250
251    fn try_borrow_mut<'l>(
252        &'l self,
253        token: &'l mut Token,
254    ) -> Result<&'l mut T, Token::ComparisonError> {
255        token
256            .compare(&self.token_id)
257            .map_likely(move |_| unsafe { &mut *self.inner.get() })
258    }
259}