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}