1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! # Purpose
//! This crate is another attempt at the `ghost-cell` / `qcell` saga of cell crates. This provides
//! an alternative to [std::cell::RefCell] that can allow interior mutability checked at compile
//! time, rather than runtime. Because Rust doesn't allow for unlimited creation of invariant
//! generics, this always comes with a rather large complexity cost. Whereas `ghost-cell` uses
//! invariant lifetimes and `qcell` can use either invariant lifetimes or newtypes, this crate
//! instead uses const generic `usize`s.
//!
//! # Pros
//! As with other `*cell` crates, this model provides interior mutability checked at compile time.
//! Unlike `ghost-cell`'s model, this crate doesn't require all of your borrows to exist in a
//! closure and, unlike `qcell::TCell`, this crate allows for more than three simultaneous borrows.
//!
//! # Cons
//!
//! First, any item that contains a `Cell` or `Token` must be generic over `const ID: usize`. You
//! may choose to get rid of this if you are **sure** that, for example, a certain instance of a
//! struct will always have `ID = 3`
//!
//! Second, in order to provide a safe API, `Token`s must be built using a `TokenBuilder` struct
//! that ensures `ID`s are unique. There may in the future be a way around this, but don't hold
//! your breath!
//!
//! Third, the use of explicit `usize` discriminants makes passing a `Cell` or `Token` to outside
//! crates inherently unsafe. It is recommended to instead send raw values, e.g., with
//! [Cell::into_inner()].
//!
//! # Example
//! ```compile_fail
//! use frankencell::*;
//! let (token1, next) = first().unwrap().token();
//! let (token2, _) = next.token();
//!
//! let a = Cell::new('a');
//! let b = Cell::new('b');
//!
//! println!("{}", a.borrow(&token1));
//! println!("{}", b.borrow(&token2));
//!
//! // The following fails to compile:
//! println!("{}", a.borrow(&token2));
//! println!("{}", b.borrow(&token1));
//! ```
//!
//! # Future improvements
//! Currently because of how `const` works, it is impossible for a `const fn` to return different
//! values on different calls. In order to generate unique IDs however, the following would have to
//! be possible:
//!
//! ```compile_fail
//! const fn inc() -> usize {
//! // Insert magic here
//! }
//!
//! #[test]
//! fn test_inc() {
//! assert_eq!(inc(), 0);
//! assert_eq!(inc(), 1);
//! assert_eq!(inc(), 2);
//!
//! // user-facing API is now significantly better
//! let token_3: Token<3> = Token::next();
//! let token_4: Token<4> = Token::next();
//! }
//! ```
//!
//! This *may* become possible when/if heap allocations are allowed in `const` contexts, but even
//! then this pattern will likely never be officially endorsed by the Rust compiler.
//!
//! It may also be possible with macros when/if macros are allowed to keep a local state
//! (rust-lang/rust issue 44034).
//!
//! # Should I use this?
//! Probably not. At the moment this is really more of a proof-of-concept. There's still a lot of
//! work that needs to go into the compiler and, even then, this may not be a viable solution.
//!
//! If you're simply looking for something that's more ergonomic than `ghost-cell` and `qcell`, the
//! `cell-family` crate seems to have a good approach.
use Once;
pub use crateTokenBuilder;
pub use crate*;
pub use crate*;
static FIRST: Once = new;
/// Entry-point into the API that allows for safe creation of unique `Token`s.
///
/// ```rust
/// # use frankencell::first;
/// assert!(first().is_some());
/// assert!(first().is_none());
/// ```
// Implementation stolen lovingly from LegionMammal978
/// Slightly more convenient way to initialize multiple tokens. Note that this currently only
/// supports the basic [Token](crate::tokens::Token) type, and a [TokenWith] must be built manually
///
/// # Example
/// init_tokens! { after first().unwrap();
/// t1, t2, t3 then next
/// }
///
/// let (with_usize, next) = next.token_with(0usize);