Skip to main content

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}