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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
//! The [`Token`] trait and its common patterns. //! //! A token is a zero-sized type, at most one instance of which ever exists. //! This concept is ubiquitous in Drone. It is used for representing //! memory-mapped registers, threads, one-time initializers, mutable statics //! ownership. While affinity (also called move-semantics in Rust) could be //! represented by Rust type-system, the other properties couldn't. Therefore //! the concept relies on the two `unsafe` contracts below. //! //! 1. *Implementing* the trait is `unsafe`, and it is the implementer //! responsibility to ensure the following: //! //! * The type must not implement [`Clone`]. //! * The type must be instantiated only inside [`Token::take`] method. //! * The type must be zero-sized. //! //! 2. *Calling* [`Token::take`] is `unsafe`, and it is the caller //! responsibility to ensure that at most one instance of the type ever exists. //! //! Tokens are often nested to minimize the usage of `unsafe` [`Token::take`] //! constructor. It is supposed to instantiate all needed tokens at the very //! beginning of the program and pass the instances further to the code. //! //! Since tokens are zero-sized, [`Token::take`] is no-op from the assembly //! perspective. Likewise passing the instance around doesn't consume the stack, //! and storing the instance inside other types doesn't consume the memory. //! //! # Simple Tokens //! //! Here is a usage example of tokens of their simplest form - `simple_token!` //! macro. In this example we implement one-timer initializers. //! //! ``` //! use drone_core::token::{simple_token, unsafe_simple_tokens, Token}; //! //! simple_token! { //! /// The token for Foo initializer. //! pub struct FooInitToken; //! } //! //! simple_token! { //! /// The token for Bar initializer. //! pub struct BarInitToken; //! } //! //! // Here is `unsafe`, we need to ensure that `FooInitToken` and `BarInitToken` //! // are not used anywhere else. //! unsafe_simple_tokens! { //! /// The group token for all initializers. //! pub struct Inits { //! FooInitToken, //! BarInitToken, //! } //! } //! //! // Define one-time initializers. They should accept tokens by-value and //! // shouldn't return them. //! //! fn init_foo(token: FooInitToken) { //! // Initialize Foo. //! } //! //! fn init_bar(token: BarInitToken) { //! // Initialize Bar. //! } //! //! // Your entry point. //! fn main() { //! // Various unsafe initializations goes here. //! unsafe { //! // Calling unsafe `take()`, we need to ensure that it is the only place //! // we call it and we are not in a cycle or recursion. //! let ini = Inits::take(); //! // Pass the token instance to your safe entry point. //! trunk(ini); //! } //! } //! //! fn trunk(ini: Inits) { //! init_foo(ini.foo_init); //! init_bar(ini.bar_init); //! // Calling them again won't compile, because the tokens were consumed. //! // init_foo(ini.foo_init); //! // init_bar(ini.bar_init); //! } //! ``` //! //! # Static Tokens //! //! Mutable statics are unsafe in Rust. One way to make them safe is to use //! interior-mutability. For example [`Mutex`](crate::sync::mutex::Mutex) //! ensures that concurrent access to the data is safe. If you don't need //! simultaneous access to the static but still need other static //! characteristics like known and stable address, you can use static tokens: //! //! ``` //! use drone_core::token::{unsafe_static_tokens, StaticToken, Token}; //! //! // Define some statics. //! static mut FOO: usize = 0; //! static mut BAR: &str = "data"; //! //! // Here is `unsafe`, we need to ensure that `FOO` and `BAR` are not used //! // anywhere else. //! unsafe_static_tokens! { //! /// The group token for all statics. //! pub struct Statics { //! FOO: usize, //! BAR: &'static str, //! } //! } //! //! // Your entry point. //! fn main() { //! // Various unsafe initializations goes here. //! unsafe { //! // Calling unsafe `take()`, we need to ensure that it is the only place //! // we call it and we are not in a cycle or recursion. //! let stc = Statics::take(); //! // Pass the token instance to your safe entry point. //! trunk(stc); //! } //! } //! //! fn trunk(mut stc: Statics) { //! // Borrow a mutable reference. //! add_one(stc.foo.get()); //! add_one(stc.foo.get()); //! assert_eq!(*stc.foo.get(), 2); //! assert_eq!(core::mem::size_of_val(&stc), 0); //! // Permanently convert to `&'static usize`. Note that `foo` is no longer a ZST. //! let foo = stc.foo.into_static(); //! // Calling it again won't compile, because the token was consumed. //! // let foo = stc.foo.into_static(); //! } //! //! fn add_one(foo: &mut usize) { //! *foo += 1; //! } //! ``` /// Defines a new simple [`Token`]. /// /// See [the module-level documentation](self) for details. #[doc(inline)] pub use drone_core_macros::simple_token; /// Defines a new token for the set of simple [`Token`]s. /// /// See [the module-level documentation](self) for details. /// /// # Safety /// /// The tokens must not be instantiated anywhere else. #[doc(inline)] pub use drone_core_macros::unsafe_simple_tokens; /// Defines a new token for the set of [`StaticToken`]s. /// /// See [the module-level documentation](self) for details. /// /// # Safety /// /// The tokens must not be instantiated anywhere else. #[doc(inline)] pub use drone_core_macros::unsafe_static_tokens; /// A zero-sized affine type, at most one instance of which ever exists. /// /// The above properties can't be expressed with Rust type-system, therefore the /// trait is marked `unsafe`, and it is the implementer responsibility to keep /// the following invariants: /// /// 1. The type must not implement [`Clone`]. /// 2. The type must be instantiated only inside [`Token::take`] method. /// 3. The type must be zero-sized. pub unsafe trait Token: Sized + Send + 'static { /// Creates the token instance. /// /// # Safety /// /// At most one instance of the token must ever exist. This invariant can't /// be expressed with Rust type-system, therefore the method is marked /// `unsafe`, and it is the caller responsibility to keep the invariant. /// /// It is recommended to call this method at the very beginning of the /// program and pass the instance further to the code. /// /// Since the type is ZST, the method is no-op from the assembly /// perspective. Likewise passing the instance around doesn't consume /// the stack, and storing the instance inside other types doesn't /// consume the memory. unsafe fn take() -> Self; } /// A token for a mutable static variable. /// /// See [the module-level documentation](self) for details. /// /// # Safety /// /// * The type must not implement [`Sync`]. /// * The target static must not be used anywhere else. pub unsafe trait StaticToken: Token + Sized + Send + 'static { /// Type of the target static. type Target: ?Sized; /// Borrows a mutable reference. fn get(&mut self) -> &mut Self::Target; /// Converts the token into a mutable reference with `'static` lifetime. fn into_static(self) -> &'static mut Self::Target; } mod compile_tests { //! ```compile_fail //! drone_core::token::simple_token!(struct Foo); //! fn main() { //! let foo = Foo { __priv: () }; //! } //! ``` //! //! ```compile_fail //! use drone_core::token::Token; //! drone_core::token::simple_token!(struct FooToken); //! drone_core::token::unsafe_simple_tokens! { //! struct Foo { //! FooToken, //! } //! } //! fn main() { //! let foo = unsafe { //! Foo { //! foo: FooToken::take(), //! __priv: (), //! } //! }; //! } //! ``` //! //! ```compile_fail //! use drone_core::token::Token; //! static mut FOO: usize = 0; //! drone_core::token::unsafe_static_tokens! { //! struct Foo { //! FOO: usize, //! } //! } //! fn main() { //! let foo = unsafe { Foo { foo: FooToken::take(), __priv: () } }; //! } //! ``` }