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
254
255
256
257
258
259
260
261
262
//! The [`Token`](token::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`](token::Token::take) method.
//!     * The type must be zero-sized.
//!
//! 2. *Calling* [`Token::take`](token::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`](token::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`](token::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: (),
    //!         }
    //!     };
    //! }
    //! ```
}