1 | use crate::cell::UnsafeCell; |
2 | use crate::mem::ManuallyDrop; |
3 | use crate::ops::Deref; |
4 | use crate::panic::{RefUnwindSafe, UnwindSafe}; |
5 | use crate::sync::Once; |
6 | use crate::{fmt, ptr}; |
7 | |
8 | use super::once::ExclusiveState; |
9 | |
10 | // We use the state of a Once as discriminant value. Upon creation, the state is |
11 | // "incomplete" and `f` contains the initialization closure. In the first call to |
12 | // `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state |
13 | // is changed to "complete". If it panics, the Once is poisoned, so none of the |
14 | // two fields is initialized. |
15 | union Data<T, F> { |
16 | value: ManuallyDrop<T>, |
17 | f: ManuallyDrop<F>, |
18 | } |
19 | |
20 | /// A value which is initialized on the first access. |
21 | /// |
22 | /// This type is a thread-safe [`LazyCell`], and can be used in statics. |
23 | /// Since initialization may be called from multiple threads, any |
24 | /// dereferencing call will block the calling thread if another |
25 | /// initialization routine is currently running. |
26 | /// |
27 | /// [`LazyCell`]: crate::cell::LazyCell |
28 | /// |
29 | /// # Examples |
30 | /// |
31 | /// Initialize static variables with `LazyLock`. |
32 | /// |
33 | /// ``` |
34 | /// #![feature(lazy_cell)] |
35 | /// |
36 | /// use std::collections::HashMap; |
37 | /// |
38 | /// use std::sync::LazyLock; |
39 | /// |
40 | /// static HASHMAP: LazyLock<HashMap<i32, String>> = LazyLock::new(|| { |
41 | /// println!("initializing" ); |
42 | /// let mut m = HashMap::new(); |
43 | /// m.insert(13, "Spica" .to_string()); |
44 | /// m.insert(74, "Hoyten" .to_string()); |
45 | /// m |
46 | /// }); |
47 | /// |
48 | /// fn main() { |
49 | /// println!("ready" ); |
50 | /// std::thread::spawn(|| { |
51 | /// println!("{:?}" , HASHMAP.get(&13)); |
52 | /// }).join().unwrap(); |
53 | /// println!("{:?}" , HASHMAP.get(&74)); |
54 | /// |
55 | /// // Prints: |
56 | /// // ready |
57 | /// // initializing |
58 | /// // Some("Spica") |
59 | /// // Some("Hoyten") |
60 | /// } |
61 | /// ``` |
62 | /// Initialize fields with `LazyLock`. |
63 | /// ``` |
64 | /// #![feature(lazy_cell)] |
65 | /// |
66 | /// use std::sync::LazyLock; |
67 | /// |
68 | /// #[derive(Debug)] |
69 | /// struct UseCellLock { |
70 | /// number: LazyLock<u32>, |
71 | /// } |
72 | /// fn main() { |
73 | /// let lock: LazyLock<u32> = LazyLock::new(|| 0u32); |
74 | /// |
75 | /// let data = UseCellLock { number: lock }; |
76 | /// println!("{}" , *data.number); |
77 | /// } |
78 | /// ``` |
79 | |
80 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
81 | pub struct LazyLock<T, F = fn() -> T> { |
82 | once: Once, |
83 | data: UnsafeCell<Data<T, F>>, |
84 | } |
85 | |
86 | impl<T, F: FnOnce() -> T> LazyLock<T, F> { |
87 | /// Creates a new lazy value with the given initializing function. |
88 | #[inline ] |
89 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
90 | pub const fn new(f: F) -> LazyLock<T, F> { |
91 | LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) } |
92 | } |
93 | |
94 | /// Creates a new lazy value that is already initialized. |
95 | #[inline ] |
96 | #[cfg (test)] |
97 | pub(crate) fn preinit(value: T) -> LazyLock<T, F> { |
98 | let once = Once::new(); |
99 | once.call_once(|| {}); |
100 | LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) } |
101 | } |
102 | |
103 | /// Consumes this `LazyLock` returning the stored value. |
104 | /// |
105 | /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. |
106 | /// |
107 | /// # Examples |
108 | /// |
109 | /// ``` |
110 | /// #![feature(lazy_cell)] |
111 | /// #![feature(lazy_cell_consume)] |
112 | /// |
113 | /// use std::sync::LazyLock; |
114 | /// |
115 | /// let hello = "Hello, World!" .to_string(); |
116 | /// |
117 | /// let lazy = LazyLock::new(|| hello.to_uppercase()); |
118 | /// |
119 | /// assert_eq!(&*lazy, "HELLO, WORLD!" ); |
120 | /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!" .to_string())); |
121 | /// ``` |
122 | #[unstable (feature = "lazy_cell_consume" , issue = "109736" )] |
123 | pub fn into_inner(mut this: Self) -> Result<T, F> { |
124 | let state = this.once.state(); |
125 | match state { |
126 | ExclusiveState::Poisoned => panic!("LazyLock instance has previously been poisoned" ), |
127 | state => { |
128 | let this = ManuallyDrop::new(this); |
129 | let data = unsafe { ptr::read(&this.data) }.into_inner(); |
130 | match state { |
131 | ExclusiveState::Incomplete => Err(ManuallyDrop::into_inner(unsafe { data.f })), |
132 | ExclusiveState::Complete => Ok(ManuallyDrop::into_inner(unsafe { data.value })), |
133 | ExclusiveState::Poisoned => unreachable!(), |
134 | } |
135 | } |
136 | } |
137 | } |
138 | |
139 | /// Forces the evaluation of this lazy value and returns a reference to |
140 | /// result. This is equivalent to the `Deref` impl, but is explicit. |
141 | /// |
142 | /// This method will block the calling thread if another initialization |
143 | /// routine is currently running. |
144 | /// |
145 | /// # Examples |
146 | /// |
147 | /// ``` |
148 | /// #![feature(lazy_cell)] |
149 | /// |
150 | /// use std::sync::LazyLock; |
151 | /// |
152 | /// let lazy = LazyLock::new(|| 92); |
153 | /// |
154 | /// assert_eq!(LazyLock::force(&lazy), &92); |
155 | /// assert_eq!(&*lazy, &92); |
156 | /// ``` |
157 | #[inline ] |
158 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
159 | pub fn force(this: &LazyLock<T, F>) -> &T { |
160 | this.once.call_once(|| { |
161 | // SAFETY: `call_once` only runs this closure once, ever. |
162 | let data = unsafe { &mut *this.data.get() }; |
163 | let f = unsafe { ManuallyDrop::take(&mut data.f) }; |
164 | let value = f(); |
165 | data.value = ManuallyDrop::new(value); |
166 | }); |
167 | |
168 | // SAFETY: |
169 | // There are four possible scenarios: |
170 | // * the closure was called and initialized `value`. |
171 | // * the closure was called and panicked, so this point is never reached. |
172 | // * the closure was not called, but a previous call initialized `value`. |
173 | // * the closure was not called because the Once is poisoned, so this point |
174 | // is never reached. |
175 | // So `value` has definitely been initialized and will not be modified again. |
176 | unsafe { &*(*this.data.get()).value } |
177 | } |
178 | } |
179 | |
180 | impl<T, F> LazyLock<T, F> { |
181 | /// Get the inner value if it has already been initialized. |
182 | fn get(&self) -> Option<&T> { |
183 | if self.once.is_completed() { |
184 | // SAFETY: |
185 | // The closure has been run successfully, so `value` has been initialized |
186 | // and will not be modified again. |
187 | Some(unsafe { &*(*self.data.get()).value }) |
188 | } else { |
189 | None |
190 | } |
191 | } |
192 | } |
193 | |
194 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
195 | impl<T, F> Drop for LazyLock<T, F> { |
196 | fn drop(&mut self) { |
197 | match self.once.state() { |
198 | ExclusiveState::Incomplete => unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) }, |
199 | ExclusiveState::Complete => unsafe { |
200 | ManuallyDrop::drop(&mut self.data.get_mut().value) |
201 | }, |
202 | ExclusiveState::Poisoned => {} |
203 | } |
204 | } |
205 | } |
206 | |
207 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
208 | impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> { |
209 | type Target = T; |
210 | |
211 | /// Dereferences the value. |
212 | /// |
213 | /// This method will block the calling thread if another initialization |
214 | /// routine is currently running. |
215 | /// |
216 | #[inline ] |
217 | fn deref(&self) -> &T { |
218 | LazyLock::force(self) |
219 | } |
220 | } |
221 | |
222 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
223 | impl<T: Default> Default for LazyLock<T> { |
224 | /// Creates a new lazy value using `Default` as the initializing function. |
225 | #[inline ] |
226 | fn default() -> LazyLock<T> { |
227 | LazyLock::new(T::default) |
228 | } |
229 | } |
230 | |
231 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
232 | impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> { |
233 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
234 | let mut d: DebugTuple<'_, '_> = f.debug_tuple(name:"LazyLock" ); |
235 | match self.get() { |
236 | Some(v: &T) => d.field(v), |
237 | None => d.field(&format_args!("<uninit>" )), |
238 | }; |
239 | d.finish() |
240 | } |
241 | } |
242 | |
243 | // We never create a `&F` from a `&LazyLock<T, F>` so it is fine |
244 | // to not impl `Sync` for `F`. |
245 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
246 | unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {} |
247 | // auto-derived `Send` impl is OK. |
248 | |
249 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
250 | impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> {} |
251 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
252 | impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F> {} |
253 | |
254 | #[cfg (test)] |
255 | mod tests; |
256 | |