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