std/sync/
lazy_lock.rs

1use super::poison::once::ExclusiveState;
2use crate::cell::UnsafeCell;
3use crate::mem::ManuallyDrop;
4use crate::ops::{Deref, DerefMut};
5use crate::panic::{RefUnwindSafe, UnwindSafe};
6use crate::sync::Once;
7use crate::{fmt, ptr};
8
9// We use the state of a Once as discriminant value. Upon creation, the state is
10// "incomplete" and `f` contains the initialization closure. In the first call to
11// `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state
12// is changed to "complete". If it panics, the Once is poisoned, so none of the
13// two fields is initialized.
14union Data<T, F> {
15    value: ManuallyDrop<T>,
16    f: ManuallyDrop<F>,
17}
18
19/// A value which is initialized on the first access.
20///
21/// This type is a thread-safe [`LazyCell`], and can be used in statics.
22/// Since initialization may be called from multiple threads, any
23/// dereferencing call will block the calling thread if another
24/// initialization routine is currently running.
25///
26/// [`LazyCell`]: crate::cell::LazyCell
27///
28/// # Poisoning
29///
30/// If the initialization closure passed to [`LazyLock::new`] panics, the lock will be poisoned.
31/// Once the lock is poisoned, any threads that attempt to access this lock (via a dereference
32/// or via an explicit call to [`force()`]) will panic.
33///
34/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key
35/// difference, however, is that poisoning in `LazyLock` is _unrecoverable_. All future accesses of
36/// the lock from other threads will panic, whereas a type in [`std::sync::poison`] like
37/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`].
38///
39/// [`force()`]: LazyLock::force
40/// [`std::sync::poison`]: crate::sync::poison
41/// [`std::sync::poison::Mutex`]: crate::sync::poison::Mutex
42/// [`PoisonError::into_inner()`]: crate::sync::poison::PoisonError::into_inner
43///
44/// # Examples
45///
46/// Initialize static variables with `LazyLock`.
47/// ```
48/// use std::sync::LazyLock;
49///
50/// // Note: static items do not call [`Drop`] on program termination, so this won't be deallocated.
51/// // this is fine, as the OS can deallocate the terminated program faster than we can free memory
52/// // but tools like valgrind might report "memory leaks" as it isn't obvious this is intentional.
53/// static DEEP_THOUGHT: LazyLock<String> = LazyLock::new(|| {
54/// # mod another_crate {
55/// #     pub fn great_question() -> String { "42".to_string() }
56/// # }
57///     // M3 Ultra takes about 16 million years in --release config
58///     another_crate::great_question()
59/// });
60///
61/// // The `String` is built, stored in the `LazyLock`, and returned as `&String`.
62/// let _ = &*DEEP_THOUGHT;
63/// ```
64///
65/// Initialize fields with `LazyLock`.
66/// ```
67/// use std::sync::LazyLock;
68///
69/// #[derive(Debug)]
70/// struct UseCellLock {
71///     number: LazyLock<u32>,
72/// }
73/// fn main() {
74///     let lock: LazyLock<u32> = LazyLock::new(|| 0u32);
75///
76///     let data = UseCellLock { number: lock };
77///     println!("{}", *data.number);
78/// }
79/// ```
80#[stable(feature = "lazy_cell", since = "1.80.0")]
81pub struct LazyLock<T, F = fn() -> T> {
82    // FIXME(nonpoison_once): if possible, switch to nonpoison version once it is available
83    once: Once,
84    data: UnsafeCell<Data<T, F>>,
85}
86
87impl<T, F: FnOnce() -> T> LazyLock<T, F> {
88    /// Creates a new lazy value with the given initializing function.
89    ///
90    /// # Examples
91    ///
92    /// ```
93    /// use std::sync::LazyLock;
94    ///
95    /// let hello = "Hello, World!".to_string();
96    ///
97    /// let lazy = LazyLock::new(|| hello.to_uppercase());
98    ///
99    /// assert_eq!(&*lazy, "HELLO, WORLD!");
100    /// ```
101    #[inline]
102    #[stable(feature = "lazy_cell", since = "1.80.0")]
103    #[rustc_const_stable(feature = "lazy_cell", since = "1.80.0")]
104    pub const fn new(f: F) -> LazyLock<T, F> {
105        LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
106    }
107
108    /// Creates a new lazy value that is already initialized.
109    #[inline]
110    #[cfg(test)]
111    pub(crate) fn preinit(value: T) -> LazyLock<T, F> {
112        let once = Once::new();
113        once.call_once(|| {});
114        LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) }
115    }
116
117    /// Consumes this `LazyLock` returning the stored value.
118    ///
119    /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
120    ///
121    /// # Panics
122    ///
123    /// Panics if the lock is poisoned.
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// #![feature(lazy_cell_into_inner)]
129    ///
130    /// use std::sync::LazyLock;
131    ///
132    /// let hello = "Hello, World!".to_string();
133    ///
134    /// let lazy = LazyLock::new(|| hello.to_uppercase());
135    ///
136    /// assert_eq!(&*lazy, "HELLO, WORLD!");
137    /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
138    /// ```
139    #[unstable(feature = "lazy_cell_into_inner", issue = "125623")]
140    pub fn into_inner(mut this: Self) -> Result<T, F> {
141        let state = this.once.state();
142        match state {
143            ExclusiveState::Poisoned => panic_poisoned(),
144            state => {
145                let this = ManuallyDrop::new(this);
146                let data = unsafe { ptr::read(&this.data) }.into_inner();
147                match state {
148                    ExclusiveState::Incomplete => Err(ManuallyDrop::into_inner(unsafe { data.f })),
149                    ExclusiveState::Complete => Ok(ManuallyDrop::into_inner(unsafe { data.value })),
150                    ExclusiveState::Poisoned => unreachable!(),
151                }
152            }
153        }
154    }
155
156    /// Forces the evaluation of this lazy value and returns a mutable reference to
157    /// the result.
158    ///
159    /// # Panics
160    ///
161    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
162    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
163    /// accesses of the lock (via [`force()`] or a dereference) to panic.
164    ///
165    /// [`new()`]: LazyLock::new
166    /// [`force()`]: LazyLock::force
167    ///
168    /// # Examples
169    ///
170    /// ```
171    /// #![feature(lazy_get)]
172    /// use std::sync::LazyLock;
173    ///
174    /// let mut lazy = LazyLock::new(|| 92);
175    ///
176    /// let p = LazyLock::force_mut(&mut lazy);
177    /// assert_eq!(*p, 92);
178    /// *p = 44;
179    /// assert_eq!(*lazy, 44);
180    /// ```
181    #[inline]
182    #[unstable(feature = "lazy_get", issue = "129333")]
183    pub fn force_mut(this: &mut LazyLock<T, F>) -> &mut T {
184        #[cold]
185        /// # Safety
186        /// May only be called when the state is `Incomplete`.
187        unsafe fn really_init_mut<T, F: FnOnce() -> T>(this: &mut LazyLock<T, F>) -> &mut T {
188            struct PoisonOnPanic<'a, T, F>(&'a mut LazyLock<T, F>);
189            impl<T, F> Drop for PoisonOnPanic<'_, T, F> {
190                #[inline]
191                fn drop(&mut self) {
192                    self.0.once.set_state(ExclusiveState::Poisoned);
193                }
194            }
195
196            // SAFETY: We always poison if the initializer panics (then we never check the data),
197            // or set the data on success.
198            let f = unsafe { ManuallyDrop::take(&mut this.data.get_mut().f) };
199            // INVARIANT: Initiated from mutable reference, don't drop because we read it.
200            let guard = PoisonOnPanic(this);
201            let data = f();
202            guard.0.data.get_mut().value = ManuallyDrop::new(data);
203            guard.0.once.set_state(ExclusiveState::Complete);
204            core::mem::forget(guard);
205            // SAFETY: We put the value there above.
206            unsafe { &mut this.data.get_mut().value }
207        }
208
209        let state = this.once.state();
210        match state {
211            ExclusiveState::Poisoned => panic_poisoned(),
212            // SAFETY: The `Once` states we completed the initialization.
213            ExclusiveState::Complete => unsafe { &mut this.data.get_mut().value },
214            // SAFETY: The state is `Incomplete`.
215            ExclusiveState::Incomplete => unsafe { really_init_mut(this) },
216        }
217    }
218
219    /// Forces the evaluation of this lazy value and returns a reference to
220    /// result. This is equivalent to the `Deref` impl, but is explicit.
221    ///
222    /// This method will block the calling thread if another initialization
223    /// routine is currently running.
224    ///
225    /// # Panics
226    ///
227    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
228    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
229    /// accesses of the lock (via [`force()`] or a dereference) to panic.
230    ///
231    /// [`new()`]: LazyLock::new
232    /// [`force()`]: LazyLock::force
233    ///
234    /// # Examples
235    ///
236    /// ```
237    /// use std::sync::LazyLock;
238    ///
239    /// let lazy = LazyLock::new(|| 92);
240    ///
241    /// assert_eq!(LazyLock::force(&lazy), &92);
242    /// assert_eq!(&*lazy, &92);
243    /// ```
244    #[inline]
245    #[stable(feature = "lazy_cell", since = "1.80.0")]
246    pub fn force(this: &LazyLock<T, F>) -> &T {
247        this.once.call_once_force(|state| {
248            if state.is_poisoned() {
249                panic_poisoned();
250            }
251
252            // SAFETY: `call_once` only runs this closure once, ever.
253            let data = unsafe { &mut *this.data.get() };
254            let f = unsafe { ManuallyDrop::take(&mut data.f) };
255            let value = f();
256            data.value = ManuallyDrop::new(value);
257        });
258
259        // SAFETY:
260        // There are four possible scenarios:
261        // * the closure was called and initialized `value`.
262        // * the closure was called and panicked, so this point is never reached.
263        // * the closure was not called, but a previous call initialized `value`.
264        // * the closure was not called because the Once is poisoned, which we handled above.
265        // So `value` has definitely been initialized and will not be modified again.
266        unsafe { &*(*this.data.get()).value }
267    }
268}
269
270impl<T, F> LazyLock<T, F> {
271    /// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or
272    /// poisoned), returns `None`.
273    ///
274    /// # Examples
275    ///
276    /// ```
277    /// #![feature(lazy_get)]
278    ///
279    /// use std::sync::LazyLock;
280    ///
281    /// let mut lazy = LazyLock::new(|| 92);
282    ///
283    /// assert_eq!(LazyLock::get_mut(&mut lazy), None);
284    /// let _ = LazyLock::force(&lazy);
285    /// *LazyLock::get_mut(&mut lazy).unwrap() = 44;
286    /// assert_eq!(*lazy, 44);
287    /// ```
288    #[inline]
289    #[unstable(feature = "lazy_get", issue = "129333")]
290    pub fn get_mut(this: &mut LazyLock<T, F>) -> Option<&mut T> {
291        // `state()` does not perform an atomic load, so prefer it over `is_complete()`.
292        let state = this.once.state();
293        match state {
294            // SAFETY:
295            // The closure has been run successfully, so `value` has been initialized.
296            ExclusiveState::Complete => Some(unsafe { &mut this.data.get_mut().value }),
297            _ => None,
298        }
299    }
300
301    /// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned),
302    /// returns `None`.
303    ///
304    /// # Examples
305    ///
306    /// ```
307    /// #![feature(lazy_get)]
308    ///
309    /// use std::sync::LazyLock;
310    ///
311    /// let lazy = LazyLock::new(|| 92);
312    ///
313    /// assert_eq!(LazyLock::get(&lazy), None);
314    /// let _ = LazyLock::force(&lazy);
315    /// assert_eq!(LazyLock::get(&lazy), Some(&92));
316    /// ```
317    #[inline]
318    #[unstable(feature = "lazy_get", issue = "129333")]
319    pub fn get(this: &LazyLock<T, F>) -> Option<&T> {
320        if this.once.is_completed() {
321            // SAFETY:
322            // The closure has been run successfully, so `value` has been initialized
323            // and will not be modified again.
324            Some(unsafe { &(*this.data.get()).value })
325        } else {
326            None
327        }
328    }
329}
330
331#[stable(feature = "lazy_cell", since = "1.80.0")]
332impl<T, F> Drop for LazyLock<T, F> {
333    fn drop(&mut self) {
334        match self.once.state() {
335            ExclusiveState::Incomplete => unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) },
336            ExclusiveState::Complete => unsafe {
337                ManuallyDrop::drop(&mut self.data.get_mut().value)
338            },
339            ExclusiveState::Poisoned => {}
340        }
341    }
342}
343
344#[stable(feature = "lazy_cell", since = "1.80.0")]
345impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
346    type Target = T;
347
348    /// Dereferences the value.
349    ///
350    /// This method will block the calling thread if another initialization
351    /// routine is currently running.
352    ///
353    /// # Panics
354    ///
355    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
356    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
357    /// accesses of the lock (via [`force()`] or a dereference) to panic.
358    ///
359    /// [`new()`]: LazyLock::new
360    /// [`force()`]: LazyLock::force
361    #[inline]
362    fn deref(&self) -> &T {
363        LazyLock::force(self)
364    }
365}
366
367#[stable(feature = "lazy_deref_mut", since = "1.89.0")]
368impl<T, F: FnOnce() -> T> DerefMut for LazyLock<T, F> {
369    /// # Panics
370    ///
371    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
372    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
373    /// accesses of the lock (via [`force()`] or a dereference) to panic.
374    ///
375    /// [`new()`]: LazyLock::new
376    /// [`force()`]: LazyLock::force
377    #[inline]
378    fn deref_mut(&mut self) -> &mut T {
379        LazyLock::force_mut(self)
380    }
381}
382
383#[stable(feature = "lazy_cell", since = "1.80.0")]
384impl<T: Default> Default for LazyLock<T> {
385    /// Creates a new lazy value using `Default` as the initializing function.
386    #[inline]
387    fn default() -> LazyLock<T> {
388        LazyLock::new(T::default)
389    }
390}
391
392#[stable(feature = "lazy_cell", since = "1.80.0")]
393impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> {
394    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395        let mut d = f.debug_tuple("LazyLock");
396        match LazyLock::get(self) {
397            Some(v) => d.field(v),
398            None => d.field(&format_args!("<uninit>")),
399        };
400        d.finish()
401    }
402}
403
404#[cold]
405#[inline(never)]
406fn panic_poisoned() -> ! {
407    panic!("LazyLock instance has previously been poisoned")
408}
409
410// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
411// to not impl `Sync` for `F`.
412#[stable(feature = "lazy_cell", since = "1.80.0")]
413unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {}
414// auto-derived `Send` impl is OK.
415
416#[stable(feature = "lazy_cell", since = "1.80.0")]
417impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> {}
418#[stable(feature = "lazy_cell", since = "1.80.0")]
419impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F> {}