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]
11fn 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    type ConstructionError;
29    type RunError;
30    type Identifier;
31    type ComparisonError;
32    /// Constructs a new Token.
33    fn new() -> Result<Self, Self::ConstructionError>;
34    /// Constructs a new Token, and provides it to the closure.
35    ///
36    /// While this should allow to provide a traitified version of `ghost-cell`, it seems the compiler only detects
37    /// the lifetime invariance with inherent methods.
38    fn with_token<R, F: FnOnce(Self) -> R>(f: F) -> Result<R, Self::RunError>;
39    /// Returns the Token's identifier, which cells may store to allow comparison.
40    fn identifier(&self) -> Self::Identifier;
41    /// Allows the cell to compare its identifier to the Token.
42    fn compare(&self, id: &Self::Identifier) -> Result<(), Self::ComparisonError>;
43}
44
45pub trait TokenCellTrait<T: ?Sized, Token: TokenTrait>: Sync {
46    /// Constructs a new cell using `token` as its key.
47    fn new(inner: T, token: &Token) -> Self
48    where
49        T: Sized;
50    /// Attempts to construct a guard which [`Deref`]s to the inner data,
51    /// but also allows recovering the `Token`.
52    fn try_guard<'l>(
53        &'l self,
54        token: &'l Token,
55    ) -> Result<TokenGuard<'l, T, Token>, Token::ComparisonError>;
56    /// Attempts to borrow the inner data.
57    ///
58    /// This only fails if the wrong token was used as a key, provided that `Token` has a runtime comparison.
59    fn try_borrow<'l>(&'l self, token: &'l Token) -> Result<&'l T, Token::ComparisonError>;
60    /// Attempts to construct a guard which [`DerefMut`]s to the inner data,
61    /// but also allows recovering the `Token`.
62    fn try_guard_mut<'l>(
63        &'l self,
64        token: &'l mut Token,
65    ) -> Result<TokenGuardMut<'l, T, Token>, Token::ComparisonError>;
66    /// Attempts to borrow the inner data mutably.
67    ///
68    /// This only fails if the wrong token was used as a key, provided that `Token` has a runtime comparison.
69    fn try_borrow_mut<'l>(
70        &'l self,
71        token: &'l mut Token,
72    ) -> Result<&'l mut T, Token::ComparisonError>;
73    /// Borrows the inner data, panicking if the wrong token was used as key.
74    fn borrow<'l>(&'l self, token: &'l Token) -> &'l T
75    where
76        Token::ComparisonError: core::fmt::Debug,
77    {
78        self.try_borrow(token).unwrap()
79    }
80    /// Borrows the inner data mutably, panicking if the wrong token was used as key.
81    fn borrow_mut<'l>(&'l self, token: &'l mut Token) -> &'l mut T
82    where
83        Token::ComparisonError: core::fmt::Debug,
84    {
85        self.try_borrow_mut(token).unwrap()
86    }
87    /// Constructs a lazy computation that can then be applied using the token.
88    fn map<'a, U, F: FnOnce(TokenGuard<'a, T, Token>) -> U>(
89        &'a self,
90        f: F,
91    ) -> TokenMap<'a, T, U, F, Self, Token> {
92        TokenMap {
93            cell: self,
94            f,
95            marker: core::marker::PhantomData,
96        }
97    }
98    /// Constructs a lazy computation that can then be applied using the token.
99    fn map_mut<'a, U, F: FnOnce(TokenGuardMut<'a, T, Token>) -> U>(
100        &'a self,
101        f: F,
102    ) -> TokenMapMut<'a, T, U, F, Self, Token> {
103        TokenMapMut {
104            cell: self,
105            f,
106            marker: core::marker::PhantomData,
107        }
108    }
109}
110
111pub struct TokenGuard<'a, T: ?Sized, Token: TokenTrait> {
112    cell: &'a TokenCell<T, Token>,
113    token: &'a Token,
114}
115impl<'a, T: ?Sized, Token: TokenTrait> TokenGuard<'a, T, Token> {
116    pub fn token(&'a self) -> &'a Token {
117        self.token
118    }
119}
120impl<'a, T: ?Sized, Token: TokenTrait> Deref for TokenGuard<'a, T, Token> {
121    type Target = T;
122    fn deref(&self) -> &Self::Target {
123        unsafe { &*self.cell.inner.get() }
124    }
125}
126
127pub struct TokenGuardMut<'a, T: ?Sized, Token: TokenTrait> {
128    cell: &'a TokenCell<T, Token>,
129    token: &'a mut Token,
130}
131impl<'a, T: ?Sized, Token: TokenTrait> TokenGuardMut<'a, T, Token> {
132    pub fn token(&'a self) -> &'a Token {
133        self.token
134    }
135    pub fn token_mut(&'a mut self) -> &'a mut Token {
136        self.token
137    }
138}
139impl<'a, T: ?Sized, Token: TokenTrait> Deref for TokenGuardMut<'a, T, Token> {
140    type Target = T;
141    fn deref(&self) -> &Self::Target {
142        unsafe { &*self.cell.inner.get() }
143    }
144}
145impl<'a, T, Token: TokenTrait> core::ops::DerefMut for TokenGuardMut<'a, T, Token> {
146    fn deref_mut(&mut self) -> &mut Self::Target {
147        unsafe { &mut *self.cell.inner.get() }
148    }
149}
150
151/// A Cell that shifts the management of access permissions to its inner value onto a `Token`.
152pub struct TokenCell<T: ?Sized, Token: TokenTrait> {
153    token_id: Token::Identifier,
154    inner: UnsafeCell<T>,
155}
156impl<T: ?Sized, Token: TokenTrait> TokenCell<T, Token> {
157    pub fn get_mut(&mut self) -> &mut T {
158        self.inner.get_mut()
159    }
160}
161impl<T: Sized, Token: TokenTrait> TokenCell<T, Token> {
162    pub fn into_inner(self) -> T {
163        self.inner.into_inner()
164    }
165}
166impl<T: ?Sized, Token: TokenTrait> Deref for TokenCell<T, Token> {
167    type Target = UnsafeCell<T>;
168    fn deref(&self) -> &Self::Target {
169        &self.inner
170    }
171}
172impl<T: ?Sized, Token: TokenTrait> DerefMut for TokenCell<T, Token> {
173    fn deref_mut(&mut self) -> &mut Self::Target {
174        &mut self.inner
175    }
176}
177
178unsafe impl<T: ?Sized, Token: TokenTrait> Sync for TokenCell<T, Token> {}
179
180impl<T: ?Sized, Token: TokenTrait> TokenCellTrait<T, Token> for TokenCell<T, Token> {
181    fn new(inner: T, token: &Token) -> Self
182    where
183        T: Sized,
184    {
185        TokenCell {
186            inner: UnsafeCell::new(inner),
187            token_id: token.identifier(),
188        }
189    }
190    fn try_guard<'l>(
191        &'l self,
192        token: &'l Token,
193    ) -> Result<TokenGuard<'l, T, Token>, <Token as TokenTrait>::ComparisonError> {
194        token
195            .compare(&self.token_id)
196            .map_likely(move |_| TokenGuard { cell: self, token })
197    }
198    fn try_borrow<'l>(&'l self, token: &'l Token) -> Result<&'l T, Token::ComparisonError> {
199        token
200            .compare(&self.token_id)
201            .map_likely(move |_| unsafe { &*self.inner.get() })
202    }
203    fn try_guard_mut<'l>(
204        &'l self,
205        token: &'l mut Token,
206    ) -> Result<TokenGuardMut<'l, T, Token>, <Token as TokenTrait>::ComparisonError> {
207        token
208            .compare(&self.token_id)
209            .map_likely(move |_| TokenGuardMut { cell: self, token })
210    }
211
212    fn try_borrow_mut<'l>(
213        &'l self,
214        token: &'l mut Token,
215    ) -> Result<&'l mut T, Token::ComparisonError> {
216        token
217            .compare(&self.token_id)
218            .map_likely(move |_| unsafe { &mut *self.inner.get() })
219    }
220}