]>
Commit | Line | Data |
---|---|---|
7cac9316 XL |
1 | // Copyright 2016 lazy-static.rs Developers |
2 | // | |
3 | // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or | |
4 | // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or | |
5 | // http://opensource.org/licenses/MIT>, at your option. This file may not be | |
6 | // copied, modified, or distributed except according to those terms. | |
7 | ||
8bb4bdeb XL |
8 | /*! |
9 | A macro for declaring lazily evaluated statics. | |
10 | ||
11 | Using this macro, it is possible to have `static`s that require code to be | |
12 | executed at runtime in order to be initialized. | |
13 | This includes anything requiring heap allocations, like vectors or hash maps, | |
14 | as well as anything that requires function calls to be computed. | |
15 | ||
16 | # Syntax | |
17 | ||
18 | ```ignore | |
19 | lazy_static! { | |
20 | [pub] static ref NAME_1: TYPE_1 = EXPR_1; | |
21 | [pub] static ref NAME_2: TYPE_2 = EXPR_2; | |
22 | ... | |
23 | [pub] static ref NAME_N: TYPE_N = EXPR_N; | |
24 | } | |
25 | ``` | |
26 | ||
27 | Attributes (including doc comments) are supported as well: | |
28 | ||
29 | ```rust | |
30 | # #[macro_use] | |
31 | # extern crate lazy_static; | |
32 | # fn main() { | |
33 | lazy_static! { | |
34 | /// This is an example for using doc comment attributes | |
35 | static ref EXAMPLE: u8 = 42; | |
36 | } | |
37 | # } | |
38 | ``` | |
39 | ||
cc61c64b | 40 | # Semantics |
8bb4bdeb XL |
41 | |
42 | For a given `static ref NAME: TYPE = EXPR;`, the macro generates a unique type that | |
43 | implements `Deref<TYPE>` and stores it in a static with name `NAME`. (Attributes end up | |
44 | attaching to this type.) | |
45 | ||
46 | On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs | |
47 | can return a reference to the same object. Note that this can lead to deadlocks | |
48 | if you have multiple lazy statics that depend on each other in their initialization. | |
49 | ||
cc61c64b XL |
50 | Apart from the lazy initialization, the resulting "static ref" variables |
51 | have generally the same properties as regular "static" variables: | |
52 | ||
53 | - Any type in them needs to fulfill the `Sync` trait. | |
54 | - If the type has a destructor, then it will not run when the process exits. | |
8bb4bdeb XL |
55 | |
56 | # Example | |
57 | ||
58 | Using the macro: | |
59 | ||
60 | ```rust | |
61 | #[macro_use] | |
62 | extern crate lazy_static; | |
63 | ||
64 | use std::collections::HashMap; | |
65 | ||
66 | lazy_static! { | |
67 | static ref HASHMAP: HashMap<u32, &'static str> = { | |
68 | let mut m = HashMap::new(); | |
69 | m.insert(0, "foo"); | |
70 | m.insert(1, "bar"); | |
71 | m.insert(2, "baz"); | |
72 | m | |
73 | }; | |
74 | static ref COUNT: usize = HASHMAP.len(); | |
75 | static ref NUMBER: u32 = times_two(21); | |
76 | } | |
77 | ||
78 | fn times_two(n: u32) -> u32 { n * 2 } | |
79 | ||
80 | fn main() { | |
81 | println!("The map has {} entries.", *COUNT); | |
82 | println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); | |
83 | println!("A expensive calculation on a static results in: {}.", *NUMBER); | |
84 | } | |
85 | ``` | |
86 | ||
87 | # Implementation details | |
88 | ||
89 | The `Deref` implementation uses a hidden static variable that is guarded by a atomic check on each access. On stable Rust, the macro may need to allocate each static on the heap. | |
90 | ||
91 | */ | |
92 | ||
abe05a73 XL |
93 | #![cfg_attr(feature="spin_no_std", feature(const_fn))] |
94 | #![cfg_attr(feature="nightly", feature(unreachable))] | |
8bb4bdeb | 95 | |
abe05a73 | 96 | #![doc(html_root_url = "https://docs.rs/lazy_static/0.2.11")] |
8bb4bdeb XL |
97 | #![no_std] |
98 | ||
99 | #[cfg(not(feature="nightly"))] | |
100 | #[doc(hidden)] | |
101 | pub mod lazy; | |
102 | ||
103 | #[cfg(all(feature="nightly", not(feature="spin_no_std")))] | |
104 | #[path="nightly_lazy.rs"] | |
105 | #[doc(hidden)] | |
106 | pub mod lazy; | |
107 | ||
108 | #[cfg(all(feature="nightly", feature="spin_no_std"))] | |
109 | #[path="core_lazy.rs"] | |
110 | #[doc(hidden)] | |
111 | pub mod lazy; | |
112 | ||
113 | #[doc(hidden)] | |
114 | pub use core::ops::Deref as __Deref; | |
115 | ||
116 | #[macro_export] | |
8bb4bdeb XL |
117 | #[doc(hidden)] |
118 | macro_rules! __lazy_static_internal { | |
abe05a73 XL |
119 | // optional visibility restrictions are wrapped in `()` to allow for |
120 | // explicitly passing otherwise implicit information about private items | |
121 | ($(#[$attr:meta])* ($($vis:tt)*) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { | |
122 | __lazy_static_internal!(@MAKE TY, $(#[$attr])*, ($($vis)*), $N); | |
123 | __lazy_static_internal!(@TAIL, $N : $T = $e); | |
124 | lazy_static!($($t)*); | |
8bb4bdeb | 125 | }; |
abe05a73 | 126 | (@TAIL, $N:ident : $T:ty = $e:expr) => { |
8bb4bdeb XL |
127 | impl $crate::__Deref for $N { |
128 | type Target = $T; | |
129 | #[allow(unsafe_code)] | |
7cac9316 | 130 | fn deref(&self) -> &$T { |
8bb4bdeb XL |
131 | unsafe { |
132 | #[inline(always)] | |
133 | fn __static_ref_initialize() -> $T { $e } | |
134 | ||
135 | #[inline(always)] | |
136 | unsafe fn __stability() -> &'static $T { | |
137 | __lazy_static_create!(LAZY, $T); | |
138 | LAZY.get(__static_ref_initialize) | |
139 | } | |
140 | __stability() | |
141 | } | |
142 | } | |
143 | } | |
144 | impl $crate::LazyStatic for $N { | |
145 | fn initialize(lazy: &Self) { | |
146 | let _ = &**lazy; | |
147 | } | |
148 | } | |
8bb4bdeb | 149 | }; |
abe05a73 XL |
150 | // `vis` is wrapped in `()` to prevent parsing ambiguity |
151 | (@MAKE TY, $(#[$attr:meta])*, ($($vis:tt)*), $N:ident) => { | |
8bb4bdeb XL |
152 | #[allow(missing_copy_implementations)] |
153 | #[allow(non_camel_case_types)] | |
154 | #[allow(dead_code)] | |
155 | $(#[$attr])* | |
abe05a73 | 156 | $($vis)* struct $N {__private_field: ()} |
8bb4bdeb | 157 | #[doc(hidden)] |
abe05a73 | 158 | $($vis)* static $N: $N = $N {__private_field: ()}; |
8bb4bdeb XL |
159 | }; |
160 | () => () | |
161 | } | |
162 | ||
163 | #[macro_export] | |
8bb4bdeb XL |
164 | macro_rules! lazy_static { |
165 | ($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { | |
abe05a73 XL |
166 | // use `()` to explicitly forward the information about private items |
167 | __lazy_static_internal!($(#[$attr])* () static ref $N : $T = $e; $($t)*); | |
8bb4bdeb XL |
168 | }; |
169 | ($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { | |
abe05a73 XL |
170 | __lazy_static_internal!($(#[$attr])* (pub) static ref $N : $T = $e; $($t)*); |
171 | }; | |
172 | ($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { | |
173 | __lazy_static_internal!($(#[$attr])* (pub ($($vis)+)) static ref $N : $T = $e; $($t)*); | |
8bb4bdeb XL |
174 | }; |
175 | () => () | |
176 | } | |
177 | ||
178 | /// Support trait for enabling a few common operation on lazy static values. | |
179 | /// | |
180 | /// This is implemented by each defined lazy static, and | |
181 | /// used by the free functions in this crate. | |
182 | pub trait LazyStatic { | |
183 | #[doc(hidden)] | |
184 | fn initialize(lazy: &Self); | |
185 | } | |
186 | ||
187 | /// Takes a shared reference to a lazy static and initializes | |
188 | /// it if it has not been already. | |
189 | /// | |
190 | /// This can be used to control the initialization point of a lazy static. | |
191 | /// | |
192 | /// Example: | |
193 | /// | |
194 | /// ```rust | |
195 | /// #[macro_use] | |
196 | /// extern crate lazy_static; | |
197 | /// | |
198 | /// lazy_static! { | |
199 | /// static ref BUFFER: Vec<u8> = (0..65537).collect(); | |
200 | /// } | |
201 | /// | |
202 | /// fn main() { | |
203 | /// lazy_static::initialize(&BUFFER); | |
204 | /// | |
205 | /// // ... | |
206 | /// work_with_initialized_data(&BUFFER); | |
207 | /// } | |
208 | /// # fn work_with_initialized_data(_: &[u8]) {} | |
209 | /// ``` | |
210 | pub fn initialize<T: LazyStatic>(lazy: &T) { | |
211 | LazyStatic::initialize(lazy); | |
212 | } |