token_cell/ghost.rs
1use core::{cell::UnsafeCell, convert::Infallible};
2
3use crate::core::TokenTrait;
4
5/// The identifier for a [`GhostToken`]-based cell is its [`InvariantLifetime`]
6#[derive(Clone, Copy)]
7pub struct InvariantLifetime<'a>(core::marker::PhantomData<UnsafeCell<&'a ()>>);
8impl<'a> InvariantLifetime<'a> {
9 const fn new() -> Self {
10 Self(core::marker::PhantomData)
11 }
12}
13
14/// A lifetime based token, inspired by `ghost_cell`.
15///
16/// Correct usage, where cells are only unlocked by providing a mutable reference to the token they were constructed with, will compile.
17/// ```rust
18/// # use token_cell::{prelude::*, ghost::GhostToken};
19/// GhostToken::with_token(|mut t1| {
20/// let c1 = TokenCell::new(1, &t1);
21/// GhostToken::with_token(|mut t2| {
22/// let c2 = TokenCell::new(1, &t2);
23/// println!("{}", *c2.borrow_mut(&mut t2));
24/// println!("{}", *c1.borrow_mut(&mut t1));
25/// })
26/// .unwrap();
27/// c1.borrow_mut(&mut t1);
28/// })
29/// .unwrap();
30/// ```
31///
32/// But using the wrong token with any given cell will fail at compile time.
33/// ```compile_fail
34/// # use token_cell::{prelude::*, ghost::GhostToken};
35/// GhostToken::with_token(|mut t1| {
36/// let c1 = TokenCell::new(1, &t1);
37/// GhostToken::with_token(|mut t2| {
38/// println!("{}", *c1.borrow_mut(&mut t2));
39/// })
40/// .unwrap();
41/// c1.borrow_mut(&mut t1);
42/// })
43/// .unwrap();
44/// ```
45/// ```compile_fail
46/// # use token_cell::{prelude::*, ghost::GhostToken};
47/// GhostToken::with_token(|mut t1| {
48/// let c1 = TokenCell::new(1, &t1);
49/// GhostToken::with_token(|mut t2| {
50/// let c2 = TokenCell::new(1, &t2);
51/// println!("{}", *c2.borrow_mut(&mut t1));
52/// println!("{}", *c1.borrow_mut(&mut t1));
53/// })
54/// .unwrap();
55/// c1.borrow_mut(&mut t1);
56/// })
57/// .unwrap();
58/// ```
59pub struct GhostToken<'brand>(InvariantLifetime<'brand>);
60impl<'brand> TokenTrait for GhostToken<'brand> {
61 type ComparisonMaySpuriouslyEq = crate::core::False;
62 type RunError = Infallible;
63 type Identifier = InvariantLifetime<'brand>;
64 type ComparisonError = Infallible;
65 type Branded<'a> = GhostToken<'a>;
66
67 /// ```rust
68 /// use token_cell::{ghost::*, prelude::*};
69 /// GhostToken::with_token(|mut t1| {
70 /// let c1 = TokenCell::new(1, &t1);
71 /// GhostToken::with_token(|mut t2| {
72 /// let c2 = TokenCell::new(1, &t2);
73 /// println!("{}", *c2.borrow_mut(&mut t2));
74 /// println!("{}", *c1.borrow_mut(&mut t1));
75 /// })
76 /// .unwrap();
77 /// c1.borrow_mut(&mut t1);
78 /// })
79 /// .unwrap();
80 /// ```
81 /// ```compile_fail
82 /// use token_cell::{ghost::*, prelude::*};
83 /// GhostToken::with_token(|mut t1| {
84 /// let c1 = TokenCell::new(1, &t1);
85 /// GhostToken::with_token(|mut t2| {
86 /// let c2 = TokenCell::new(1, &t2);
87 /// println!("{}", *c2.borrow_mut(&mut t2));
88 /// println!("{}", *c1.borrow_mut(&mut t2));
89 /// })
90 /// .unwrap();
91 /// c1.borrow_mut(&mut t1);
92 /// })
93 /// .unwrap();
94 /// ```
95 fn with_token<R, F: for<'a> FnOnce(Self::Branded<'a>) -> R>(f: F) -> Result<R, Self::RunError> {
96 Ok(f(Self(InvariantLifetime::new())))
97 }
98
99 fn identifier(&self) -> InvariantLifetime<'brand> {
100 self.0
101 }
102
103 fn compare(&self, _: &InvariantLifetime<'brand>) -> Result<(), Self::ComparisonError> {
104 Ok(())
105 }
106}