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}