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 ConstructionError = ();
62    type RunError = Infallible;
63    type Identifier = InvariantLifetime<'brand>;
64    type ComparisonError = Infallible;
65    type Branded<'a> = GhostToken<'a>;
66    fn new() -> Result<Self, Self::ConstructionError> {
67        Err(())
68    }
69    /// ```rust
70    /// use token_cell::{ghost::*, prelude::*};
71    /// GhostToken::with_token(|mut t1| {
72    ///     let c1 = TokenCell::new(1, &t1);
73    ///     GhostToken::with_token(|mut t2| {
74    ///         let c2 = TokenCell::new(1, &t2);
75    ///         println!("{}", *c2.borrow_mut(&mut t2));
76    ///         println!("{}", *c1.borrow_mut(&mut t1));
77    ///     })
78    ///     .unwrap();
79    ///     c1.borrow_mut(&mut t1);
80    /// })
81    /// .unwrap();
82    /// ```
83    /// ```compile_fail
84    /// use token_cell::{ghost::*, prelude::*};
85    /// GhostToken::with_token(|mut t1| {
86    ///     let c1 = TokenCell::new(1, &t1);
87    ///     GhostToken::with_token(|mut t2| {
88    ///         let c2 = TokenCell::new(1, &t2);
89    ///         println!("{}", *c2.borrow_mut(&mut t2));
90    ///         println!("{}", *c1.borrow_mut(&mut t2));
91    ///     })
92    ///     .unwrap();
93    ///     c1.borrow_mut(&mut t1);
94    /// })
95    /// .unwrap();
96    /// ```
97    fn with_token<R, F: for<'a> FnOnce(Self::Branded<'a>) -> R>(f: F) -> Result<R, Self::RunError> {
98        Ok(f(Self(InvariantLifetime::new())))
99    }
100
101    fn identifier(&self) -> InvariantLifetime<'brand> {
102        self.0
103    }
104
105    fn compare(&self, _: &InvariantLifetime<'brand>) -> Result<(), Self::ComparisonError> {
106        Ok(())
107    }
108}