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}