init_token/
lib.rs

1#![doc = include_str!("../README.md")]
2#![forbid(rust_2018_idioms, unsafe_op_in_unsafe_fn)]
3
4pub mod init;
5pub mod init_big;
6#[doc(hidden)]
7pub mod sync_unsafe_cell;
8#[doc(hidden)]
9pub mod token;
10
11/// A runtime-initialized `static` with zero access overhead protected by an access token.
12///
13/// This macro should be the default choice. Use [`init_big!`] only if the static value
14/// is too big to pass on stack.
15///
16/// See [the crate-level documentation](crate) for details.
17///
18/// ```
19/// init_token::init! {
20///     /// The magic token to get `MY_STATIC` working.
21///     pub token MyToken;
22///     /// My cool static.
23///     pub static MY_STATIC: i32 = "-123".parse().unwrap();
24/// }
25///
26/// let token = MY_STATIC.init();
27/// assert_eq!(*token, -123);
28/// let static_ref: &'static i32 = MyToken::static_ref(token);
29/// assert_eq!(*static_ref, -123);
30/// // We can call `init()` twice, but then it has to check whether the `static`
31/// // is initialized. Therefore, prefer using existing tokens if possible.
32/// assert_eq!(*MY_STATIC.init(), -123);
33/// ```
34#[macro_export]
35macro_rules! init {
36    {
37        $( #[doc = $($token_doc:tt)*] )*
38        $token_vis:vis token $token_name:ident;
39        $( #[doc = $($doc:tt)*] )*
40        $vis:vis static $name:ident : $type:ty = $init:expr;
41    } => {
42        $crate::token! {
43            $( #[doc = $($token_doc)*] )*
44            $token_vis token $token_name by init($name : $type);
45        }
46
47        $( #[doc = $($doc)*] )*
48        $vis static $name : $crate::init::Static<$type, $token_name> =
49            $crate::init::Static::new(|| $init);
50    };
51}
52
53/// A runtime-initialized `static` with zero access overhead protected by an access token.
54///
55/// This macro should only used if the static value is too big to pass on stack. Use [`init!`]
56/// otherwise.
57///
58/// See [the crate-level documentation](crate) for details.
59///
60/// ```
61/// init_token::init_big! {
62///     /// The magic token to get `MY_STATIC` working.
63///     pub token MyToken;
64///     /// My cool static.
65///     pub static MY_STATIC: i32 = 0;
66///
67///     init(my_static) {
68///         *my_static = "-123".parse().unwrap();
69///     }
70/// }
71///
72/// let token = MY_STATIC.init();
73/// assert_eq!(*token, -123);
74/// let static_ref: &'static i32 = MyToken::static_ref(token);
75/// assert_eq!(*static_ref, -123);
76/// // We can call `init()` twice, but then it has to check whether the `static`
77/// // is initialized. Therefore, prefer using existing tokens if possible.
78/// assert_eq!(*MY_STATIC.init(), -123);
79/// ```
80#[macro_export]
81macro_rules! init_big {
82    {
83        $( #[doc = $($token_doc:tt)*] )*
84        $token_vis:vis token $token_name:ident;
85        $( #[doc = $($doc:tt)*] )*
86        $vis:vis static $name:ident : $type:ty = $const_init:expr;
87
88        init($runtime_init_param_name:ident) { $($runtime_init:tt)+ }
89    } => {
90        $crate::token! {
91            $( #[doc = $($token_doc)*] )*
92            $token_vis token $token_name by init_big($name : $type);
93        }
94
95        $( #[doc = $($doc)*] )*
96        $vis static $name : $crate::init_big::Static<$type, $token_name> =
97            $crate::init_big::Static::new(
98                $const_init,
99                |value| {
100                    // SAFETY: We're allowed to do that, see `init_big::Static::new()`.
101                    #[allow(unsafe_code)]
102                    let value = unsafe { $crate::sync_unsafe_cell::SyncUnsafeCell::get_mut(value) };
103                    (|$runtime_init_param_name: &mut $type| { $($runtime_init)+ })(value)
104                },
105            );
106    };
107}
108
109/// An example of the usage and generated docs.
110///
111/// Example code:
112/// ```
113/// init_token::init! {
114///     /// The magic token to get [`MY_STATIC`] working.
115///     pub token MyToken;
116///     /// My cool static.
117///     pub static MY_STATIC: i32 = std::env::var("MY_STATIC").unwrap().parse().unwrap();
118/// }
119///
120/// init_token::init_big! {
121///     /// The magic token to get [`MY_BIG_STATIC`] working.
122///     pub token MyBigToken;
123///     /// My cool static.
124///     pub static MY_BIG_STATIC: i32 = 0;
125///
126///     init(s) {
127///         *s = std::env::var("MY_STATIC").unwrap().parse().unwrap();
128///     }
129/// }
130/// ```
131#[cfg(doc)]
132pub mod example {
133    init! {
134        /// The magic token to get [`MY_STATIC`] working.
135        pub token MyToken;
136        /// My cool static.
137        pub static MY_STATIC: i32 = std::env::var("MY_STATIC").unwrap().parse().unwrap();
138    }
139
140    init_big! {
141        /// The magic token to get [`MY_BIG_STATIC`] working.
142        pub token MyBigToken;
143        /// My cool static.
144        pub static MY_BIG_STATIC: i32 = 0;
145
146        init(s) {
147            *s = std::env::var("MY_STATIC").unwrap().parse().unwrap();
148        }
149    }
150}