Skip to main content

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
27/// A token that isn't intrinsically tied to a scope.
28///
29/// Most token types aren't, but some like [`GhostToken`] are.
30pub trait UnscopedToken: TokenTrait {
31    /// Constructing a token may fail.
32    type ConstructionError;
33
34    /// Constructs a new Token.
35    ///
36    /// # Errors
37    /// Some token implementations may chose to be constructible only once, or only while holding a given lock.
38    fn try_new() -> Result<Self, Self::ConstructionError>;
39
40    /// Constructs a new Token. This method may be used instead of [`UnscopedToken::try_new`] when .
41    fn new() -> Self
42    where
43        Self: UnscopedToken<ConstructionError = core::convert::Infallible>,
44    {
45        let Ok(this) = Self::try_new();
46        this
47    }
48}
49
50pub use sealed::{False, True};
51pub(crate) mod sealed {
52    pub trait Boolean {}
53    /// A type that represents `true`.
54    pub struct True;
55    /// A type that represents `false`.
56    pub struct False;
57    impl Boolean for True {}
58    impl Boolean for False {}
59}
60
61/// A trait for tokens
62pub trait TokenTrait: Sized {
63    /// Whether or not comparison between two distinct token could yield `eq`.
64    ///
65    /// This can be the case for tokens that can be constructed with [`UnscopedToken`] an arbitrary amount of times,
66    /// but aren't guaranteed to have unique identifiers distinguishing them:
67    /// - Instances of the types created by [`unsafe_token`](crate::unsafe_token), for example, are indistinguishable at both compile and runtime;
68    ///   accidentally using two distinct instances to gain access to a same cell could cause undefined behaviour if done simultaneously.
69    /// - Instances of the types created by [`runtime_token`](crate::runtime_token) are identified by a cyclic counter (`u16`` by default);
70    ///   while unlikely, you could create two distinct instances with a same internal id by overflowing the static counter used to construct them.
71    type ComparisonMaySpuriouslyEq: sealed::Boolean;
72
73    /// [`TokenTrait::with_token`] may fail, typically if construction failed.
74    ///
75    /// Some types, like [`GhostToken`](crate::ghost::GhostToken) are inconstructible with [`UnscopedToken`], but cannot fail to run, hence the distinction.
76    type RunError;
77
78    /// Lets a [`TokenCell`] keep track of the token.
79    ///
80    /// In most cases, this is a ZST in release mode.
81    type Identifier;
82
83    /// [`core::convert::Infallible`] unless [`TokenTrait::compare`] is fallible (ie. comparison is done at runtime).
84    type ComparisonError;
85
86    /// Rebrands the token, this is necessary for [`GhostToken`](crate::ghost::GhostToken) to function properly
87    type Branded<'a>;
88
89    /// Constructs a new, lifetime-branded Token, and provides it to the closure.
90    ///
91    /// 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.
92    ///
93    /// # Errors
94    /// If construction failed, so will this.
95    fn with_token<R, F: for<'a> FnOnce(Self::Branded<'a>) -> R>(f: F) -> Result<R, Self::RunError>;
96
97    /// Returns the Token's identifier, which cells may store to allow comparison.
98    fn identifier(&self) -> Self::Identifier;
99
100    /// Allows the cell to compare its identifier to the Token.
101    ///
102    /// # Errors
103    /// If a wrong token was mistakenly passed to the cell.
104    fn compare(&self, id: &Self::Identifier) -> Result<(), Self::ComparisonError>;
105}
106
107/// Common ways to interract with a [`TokenCell`].
108///
109/// 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`].
110pub trait UnsafeTokenCellTrait<T: ?Sized, Token: TokenTrait<ComparisonMaySpuriouslyEq = True>>:
111    Sync
112{
113    /// Attempts to construct a guard which [`Deref`]s to the inner data,
114    /// but also allows recovering the `Token`.
115    ///
116    /// # Safety
117    /// `token` must refer to the _exact same_ instance of `Token` as that which was used to call [`Self::new`].
118    ///
119    /// # Errors
120    /// If the token provides runtime checking and detects that `self` was constructed with another token.
121    ///
122    /// If such an error is ever raised, it should be treated as a high priority bug in your application,
123    /// as that would indicate that the safety requirement was not met, but was detected before Undefined Behaviour
124    /// could be triggered.
125    unsafe fn try_guard<'l>(
126        &'l self,
127        token: &'l Token,
128    ) -> Result<TokenGuard<'l, T, Token>, Token::ComparisonError>;
129
130    /// Attempts to borrow the inner data.
131    ///
132    /// # Safety
133    /// `token` must refer to the _exact same_ instance of `Token` as that which was used to call [`Self::new`].
134    ///
135    /// # Errors
136    /// If the token provides runtime checking and detects that `self` was constructed with another token.
137    unsafe fn try_borrow<'l>(&'l self, token: &'l Token) -> Result<&'l T, Token::ComparisonError>;
138
139    /// Attempts to construct a guard which [`DerefMut`]s to the inner data,
140    /// but also allows recovering the `Token`.
141    ///
142    /// # Safety
143    /// `token` must refer to the _exact same_ instance of `Token` as that which was used to call [`Self::new`].
144    ///
145    /// # Errors
146    /// If the token provides runtime checking and detects that `self` was constructed with another token.
147    unsafe fn try_guard_mut<'l>(
148        &'l self,
149        token: &'l mut Token,
150    ) -> Result<TokenGuardMut<'l, T, Token>, Token::ComparisonError>;
151
152    /// Attempts to borrow the inner data mutably.
153    ///
154    /// # Safety
155    /// `token` must refer to the _exact same_ instance of `Token` as that which was used to call [`Self::new`].
156    ///
157    /// # Errors
158    /// If the token provides runtime checking and detects that `self` was constructed with another token.
159    unsafe fn try_borrow_mut<'l>(
160        &'l self,
161        token: &'l mut Token,
162    ) -> Result<&'l mut T, Token::ComparisonError>;
163
164    /// Borrows the inner data, panicking if the wrong token was used as key.
165    ///
166    /// # Safety
167    /// `token` must refer to the _exact same_ instance of `Token` as that which was used to call [`Self::new`].
168    unsafe fn borrow<'l>(&'l self, token: &'l Token) -> &'l T
169    where
170        Token::ComparisonError: core::fmt::Debug,
171    {
172        self.try_borrow(token).unwrap()
173    }
174
175    /// Borrows the inner data mutably, panicking if the wrong token was used as key.
176    ///
177    /// # Safety
178    /// `token` must refer to the _exact same_ instance of `Token` as that which was used to call [`Self::new`].
179    unsafe fn borrow_mut<'l>(&'l self, token: &'l mut Token) -> &'l mut T
180    where
181        Token::ComparisonError: core::fmt::Debug,
182    {
183        self.try_borrow_mut(token).unwrap()
184    }
185
186    /// Constructs a lazy computation that can then be applied using the token.
187    ///
188    /// # Safety
189    /// `token` must refer to the _exact same_ instance of `Token` as that which was used to call [`Self::new`].
190    unsafe fn map<'a, U, F: FnOnce(TokenGuard<'a, T, Token>) -> U>(
191        &'a self,
192        f: F,
193    ) -> TokenMap<'a, T, U, F, Self, Token, True> {
194        TokenMap {
195            cell: self,
196            f,
197            marker: core::marker::PhantomData,
198        }
199    }
200
201    /// Constructs a lazy computation that can then be applied using the token.
202    ///
203    /// # Safety
204    /// `token` must refer to the _exact same_ instance of `Token` as that which was used to call [`Self::new`].
205    unsafe fn map_mut<'a, U, F: FnOnce(TokenGuardMut<'a, T, Token>) -> U>(
206        &'a self,
207        f: F,
208    ) -> TokenMapMut<'a, T, U, F, Self, Token, True> {
209        TokenMapMut {
210            cell: self,
211            f,
212            marker: core::marker::PhantomData,
213        }
214    }
215}
216
217/// Common ways to interract with a [`TokenCell`].
218///
219/// 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`].
220pub trait TokenCellTrait<T: ?Sized, Token: TokenTrait<ComparisonMaySpuriouslyEq = False>> {
221    /// Attempts to construct a guard which [`Deref`]s to the inner data,
222    /// but also allows recovering the `Token`.
223    ///
224    /// # Errors
225    /// If the token provides runtime checking and detects that `self` was constructed with another token.
226    fn try_guard<'l>(
227        &'l self,
228        token: &'l Token,
229    ) -> Result<TokenGuard<'l, T, Token>, Token::ComparisonError>;
230
231    /// Attempts to borrow the inner data.
232    ///
233    /// # Errors
234    /// If the token provides runtime checking and detects that `self` was constructed with another token.
235    fn try_borrow<'l>(&'l self, token: &'l Token) -> Result<&'l T, Token::ComparisonError>;
236
237    /// Attempts to construct a guard which [`DerefMut`]s to the inner data,
238    /// but also allows recovering the `Token`.
239    ///
240    /// # Errors
241    /// If the token provides runtime checking and detects that `self` was constructed with another token.
242    fn try_guard_mut<'l>(
243        &'l self,
244        token: &'l mut Token,
245    ) -> Result<TokenGuardMut<'l, T, Token>, Token::ComparisonError>;
246
247    /// Attempts to borrow the inner data mutably.
248    ///
249    /// # Errors
250    /// If the token provides runtime checking and detects that `self` was constructed with another token.
251    fn try_borrow_mut<'l>(
252        &'l self,
253        token: &'l mut Token,
254    ) -> Result<&'l mut T, Token::ComparisonError>;
255
256    /// Borrows the inner data, panicking if the wrong token was used as key.
257    fn borrow<'l>(&'l self, token: &'l Token) -> &'l T
258    where
259        Token::ComparisonError: core::fmt::Debug,
260    {
261        self.try_borrow(token).unwrap()
262    }
263
264    /// Borrows the inner data mutably, panicking if the wrong token was used as key.
265    fn borrow_mut<'l>(&'l self, token: &'l mut Token) -> &'l mut T
266    where
267        Token::ComparisonError: core::fmt::Debug,
268    {
269        self.try_borrow_mut(token).unwrap()
270    }
271
272    /// Constructs a lazy computation that can then be applied using the token.
273    fn map<'a, U, F: FnOnce(TokenGuard<'a, T, Token>) -> U>(
274        &'a self,
275        f: F,
276    ) -> TokenMap<'a, T, U, F, Self, Token, False> {
277        TokenMap {
278            cell: self,
279            f,
280            marker: core::marker::PhantomData,
281        }
282    }
283
284    /// Constructs a lazy computation that can then be applied using the token.
285    fn map_mut<'a, U, F: FnOnce(TokenGuardMut<'a, T, Token>) -> U>(
286        &'a self,
287        f: F,
288    ) -> TokenMapMut<'a, T, U, F, Self, Token, False> {
289        TokenMapMut {
290            cell: self,
291            f,
292            marker: core::marker::PhantomData,
293        }
294    }
295}
296
297/// A guard that allows immutably borrowing the cell's value, as well as its token.
298pub struct TokenGuard<'a, T: ?Sized, Token: TokenTrait> {
299    cell: &'a TokenCell<T, Token>,
300    token: &'a Token,
301}
302impl<'a, T: ?Sized, Token: TokenTrait> TokenGuard<'a, T, Token> {
303    /// Reborrows the token immutably.
304    pub const fn token(&self) -> &Token {
305        self.token
306    }
307}
308impl<'a, T: ?Sized, Token: TokenTrait> Deref for TokenGuard<'a, T, Token> {
309    type Target = T;
310    fn deref(&self) -> &Self::Target {
311        unsafe { &*self.cell.inner.get() }
312    }
313}
314
315/// A guard that allows mutably borrowing the cell's value, as well as its token.
316pub struct TokenGuardMut<'a, T: ?Sized, Token: TokenTrait> {
317    cell: &'a TokenCell<T, Token>,
318    token: &'a mut Token,
319}
320impl<'a, T: ?Sized, Token: TokenTrait> TokenGuardMut<'a, T, Token> {
321    /// Reborrows the token immutably.
322    pub const fn token(&self) -> &Token {
323        self.token
324    }
325    /// Reborrows the token mutably.
326    #[rustversion::attr(since(1.83), const)]
327    pub fn token_mut(&mut self) -> &mut Token {
328        self.token
329    }
330}
331impl<'a, T: ?Sized, Token: TokenTrait> Deref for TokenGuardMut<'a, T, Token> {
332    type Target = T;
333    fn deref(&self) -> &Self::Target {
334        unsafe { &*self.cell.inner.get() }
335    }
336}
337impl<'a, T, Token: TokenTrait> core::ops::DerefMut for TokenGuardMut<'a, T, Token> {
338    fn deref_mut(&mut self) -> &mut Self::Target {
339        unsafe { &mut *self.cell.inner.get() }
340    }
341}
342
343/// A Cell that shifts the management of access permissions to its inner value onto a `Token`.
344pub struct TokenCell<T: ?Sized, Token: TokenTrait> {
345    token_id: Token::Identifier,
346    inner: UnsafeCell<T>,
347}
348impl<T: ?Sized, Token: TokenTrait> TokenCell<T, Token> {
349    /// While cells are typically behind immutable references,
350    /// obtaining a mutable reference to one is still proof of unique access.
351    #[rustversion::attr(since(1.83), const)]
352    pub fn get_mut(&mut self) -> &mut T {
353        self.inner.get_mut()
354    }
355}
356impl<T: Sized, Token: TokenTrait> TokenCell<T, Token> {
357    /// Unwraps the value from the cell.
358    ///
359    /// Full ownership of the cell is sufficient proof that the inner value can be recovered.
360    pub fn into_inner(self) -> T {
361        self.inner.into_inner()
362    }
363}
364impl<T: ?Sized, Token: TokenTrait> Deref for TokenCell<T, Token> {
365    type Target = UnsafeCell<T>;
366    fn deref(&self) -> &Self::Target {
367        &self.inner
368    }
369}
370impl<T: ?Sized, Token: TokenTrait> DerefMut for TokenCell<T, Token> {
371    fn deref_mut(&mut self) -> &mut Self::Target {
372        &mut self.inner
373    }
374}
375
376unsafe impl<T: ?Sized, Token: TokenTrait> Sync for TokenCell<T, Token> {}
377
378impl<T: ?Sized, Token: TokenTrait<ComparisonMaySpuriouslyEq = True>> UnsafeTokenCellTrait<T, Token>
379    for TokenCell<T, Token>
380{
381    unsafe fn try_guard<'l>(
382        &'l self,
383        token: &'l Token,
384    ) -> Result<TokenGuard<'l, T, Token>, <Token as TokenTrait>::ComparisonError> {
385        token
386            .compare(&self.token_id)
387            .map_likely(move |_| TokenGuard { cell: self, token })
388    }
389    unsafe fn try_borrow<'l>(&'l self, token: &'l Token) -> Result<&'l T, Token::ComparisonError> {
390        token
391            .compare(&self.token_id)
392            .map_likely(move |_| unsafe { &*self.inner.get() })
393    }
394    unsafe fn try_guard_mut<'l>(
395        &'l self,
396        token: &'l mut Token,
397    ) -> Result<TokenGuardMut<'l, T, Token>, <Token as TokenTrait>::ComparisonError> {
398        token
399            .compare(&self.token_id)
400            .map_likely(move |_| TokenGuardMut { cell: self, token })
401    }
402
403    unsafe fn try_borrow_mut<'l>(
404        &'l self,
405        token: &'l mut Token,
406    ) -> Result<&'l mut T, Token::ComparisonError> {
407        token
408            .compare(&self.token_id)
409            .map_likely(move |_| unsafe { &mut *self.inner.get() })
410    }
411}
412
413impl<T: ?Sized, Token: TokenTrait<ComparisonMaySpuriouslyEq = False>> TokenCellTrait<T, Token>
414    for TokenCell<T, Token>
415{
416    fn try_guard<'l>(
417        &'l self,
418        token: &'l Token,
419    ) -> Result<TokenGuard<'l, T, Token>, <Token as TokenTrait>::ComparisonError> {
420        token
421            .compare(&self.token_id)
422            .map_likely(move |_| TokenGuard { cell: self, token })
423    }
424    fn try_borrow<'l>(&'l self, token: &'l Token) -> Result<&'l T, Token::ComparisonError> {
425        token
426            .compare(&self.token_id)
427            .map_likely(move |_| unsafe { &*self.inner.get() })
428    }
429    fn try_guard_mut<'l>(
430        &'l self,
431        token: &'l mut Token,
432    ) -> Result<TokenGuardMut<'l, T, Token>, <Token as TokenTrait>::ComparisonError> {
433        token
434            .compare(&self.token_id)
435            .map_likely(move |_| TokenGuardMut { cell: self, token })
436    }
437
438    fn try_borrow_mut<'l>(
439        &'l self,
440        token: &'l mut Token,
441    ) -> Result<&'l mut T, Token::ComparisonError> {
442        token
443            .compare(&self.token_id)
444            .map_likely(move |_| unsafe { &mut *self.inner.get() })
445    }
446}
447
448impl<T, Token: TokenTrait> TokenCell<T, Token> {
449    //// Constructs a new [`TokenCell`] keyed by `token`.
450    ///
451    /// All calls to [`UnsafeTokenCellTrait`] or [`TokenCellTrait`]'s methods on the returned value MUST use the same instance of `token`
452    /// as passed to this constructor.
453    pub fn new(value: T, token: &Token) -> Self {
454        TokenCell {
455            inner: UnsafeCell::new(value),
456            token_id: token.identifier(),
457        }
458    }
459}