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}