use super::poison::once::ExclusiveState; use crate::cell::UnsafeCell; use crate::mem::ManuallyDrop; use crate::ops::{Deref, DerefMut}; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sync::Once; use crate::{fmt, ptr}; // We use the state of a Once as discriminant value. Upon creation, the state is // "incomplete" and `f` contains the initialization closure. In the first call to // `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state // is changed to "complete". If it panics, the Once is poisoned, so none of the // two fields is initialized. union Data { value: ManuallyDrop, f: ManuallyDrop, } /// A value which is initialized on the first access. /// /// This type is a thread-safe [`LazyCell`], and can be used in statics. /// Since initialization may be called from multiple threads, any /// dereferencing call will block the calling thread if another /// initialization routine is currently running. /// /// [`LazyCell`]: crate::cell::LazyCell /// /// # Poisoning /// /// If the initialization closure passed to [`LazyLock::new`] panics, the lock will be poisoned. /// Once the lock is poisoned, any threads that attempt to access this lock (via a dereference /// or via an explicit call to [`force()`]) will panic. /// /// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key /// difference, however, is that poisoning in `LazyLock` is _unrecoverable_. All future accesses of /// the lock from other threads will panic, whereas a type in [`std::sync::poison`] like /// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`]. /// /// [`force()`]: LazyLock::force /// [`std::sync::poison`]: crate::sync::poison /// [`std::sync::poison::Mutex`]: crate::sync::poison::Mutex /// [`PoisonError::into_inner()`]: crate::sync::poison::PoisonError::into_inner /// /// # Examples /// /// Initialize static variables with `LazyLock`. /// ``` /// use std::sync::LazyLock; /// /// // Note: static items do not call [`Drop`] on program termination, so this won't be deallocated. /// // this is fine, as the OS can deallocate the terminated program faster than we can free memory /// // but tools like valgrind might report "memory leaks" as it isn't obvious this is intentional. /// static DEEP_THOUGHT: LazyLock = LazyLock::new(|| { /// # mod another_crate { /// # pub fn great_question() -> String { "42".to_string() } /// # } /// // M3 Ultra takes about 16 million years in --release config /// another_crate::great_question() /// }); /// /// // The `String` is built, stored in the `LazyLock`, and returned as `&String`. /// let _ = &*DEEP_THOUGHT; /// ``` /// /// Initialize fields with `LazyLock`. /// ``` /// use std::sync::LazyLock; /// /// #[derive(Debug)] /// struct UseCellLock { /// number: LazyLock, /// } /// fn main() { /// let lock: LazyLock = LazyLock::new(|| 0u32); /// /// let data = UseCellLock { number: lock }; /// println!("{}", *data.number); /// } /// ``` #[stable(feature = "lazy_cell", since = "1.80.0")] pub struct LazyLock T> { // FIXME(nonpoison_once): if possible, switch to nonpoison version once it is available once: Once, data: UnsafeCell>, } impl T> LazyLock { /// Creates a new lazy value with the given initializing function. /// /// # Examples /// /// ``` /// use std::sync::LazyLock; /// /// let hello = "Hello, World!".to_string(); /// /// let lazy = LazyLock::new(|| hello.to_uppercase()); /// /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// ``` #[inline] #[stable(feature = "lazy_cell", since = "1.80.0")] #[rustc_const_stable(feature = "lazy_cell", since = "1.80.0")] pub const fn new(f: F) -> LazyLock { LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) } } /// Creates a new lazy value that is already initialized. #[inline] #[cfg(test)] pub(crate) fn preinit(value: T) -> LazyLock { let once = Once::new(); once.call_once(|| {}); LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) } } /// Consumes this `LazyLock` returning the stored value. /// /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. /// /// # Panics /// /// Panics if the lock is poisoned. /// /// # Examples /// /// ``` /// #![feature(lazy_cell_into_inner)] /// /// use std::sync::LazyLock; /// /// let hello = "Hello, World!".to_string(); /// /// let lazy = LazyLock::new(|| hello.to_uppercase()); /// /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); /// ``` #[unstable(feature = "lazy_cell_into_inner", issue = "125623")] pub fn into_inner(mut this: Self) -> Result { let state = this.once.state(); match state { ExclusiveState::Poisoned => panic_poisoned(), state => { let this = ManuallyDrop::new(this); let data = unsafe { ptr::read(&this.data) }.into_inner(); match state { ExclusiveState::Incomplete => Err(ManuallyDrop::into_inner(unsafe { data.f })), ExclusiveState::Complete => Ok(ManuallyDrop::into_inner(unsafe { data.value })), ExclusiveState::Poisoned => unreachable!(), } } } } /// Forces the evaluation of this lazy value and returns a mutable reference to /// the result. /// /// # Panics /// /// If the initialization closure panics (the one that is passed to the [`new()`] method), the /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future /// accesses of the lock (via [`force()`] or a dereference) to panic. /// /// [`new()`]: LazyLock::new /// [`force()`]: LazyLock::force /// /// # Examples /// /// ``` /// #![feature(lazy_get)] /// use std::sync::LazyLock; /// /// let mut lazy = LazyLock::new(|| 92); /// /// let p = LazyLock::force_mut(&mut lazy); /// assert_eq!(*p, 92); /// *p = 44; /// assert_eq!(*lazy, 44); /// ``` #[inline] #[unstable(feature = "lazy_get", issue = "129333")] pub fn force_mut(this: &mut LazyLock) -> &mut T { #[cold] /// # Safety /// May only be called when the state is `Incomplete`. unsafe fn really_init_mut T>(this: &mut LazyLock) -> &mut T { struct PoisonOnPanic<'a, T, F>(&'a mut LazyLock); impl Drop for PoisonOnPanic<'_, T, F> { #[inline] fn drop(&mut self) { self.0.once.set_state(ExclusiveState::Poisoned); } } // SAFETY: We always poison if the initializer panics (then we never check the data), // or set the data on success. let f = unsafe { ManuallyDrop::take(&mut this.data.get_mut().f) }; // INVARIANT: Initiated from mutable reference, don't drop because we read it. let guard = PoisonOnPanic(this); let data = f(); guard.0.data.get_mut().value = ManuallyDrop::new(data); guard.0.once.set_state(ExclusiveState::Complete); core::mem::forget(guard); // SAFETY: We put the value there above. unsafe { &mut this.data.get_mut().value } } let state = this.once.state(); match state { ExclusiveState::Poisoned => panic_poisoned(), // SAFETY: The `Once` states we completed the initialization. ExclusiveState::Complete => unsafe { &mut this.data.get_mut().value }, // SAFETY: The state is `Incomplete`. ExclusiveState::Incomplete => unsafe { really_init_mut(this) }, } } /// Forces the evaluation of this lazy value and returns a reference to /// result. This is equivalent to the `Deref` impl, but is explicit. /// /// This method will block the calling thread if another initialization /// routine is currently running. /// /// # Panics /// /// If the initialization closure panics (the one that is passed to the [`new()`] method), the /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future /// accesses of the lock (via [`force()`] or a dereference) to panic. /// /// [`new()`]: LazyLock::new /// [`force()`]: LazyLock::force /// /// # Examples /// /// ``` /// use std::sync::LazyLock; /// /// let lazy = LazyLock::new(|| 92); /// /// assert_eq!(LazyLock::force(&lazy), &92); /// assert_eq!(&*lazy, &92); /// ``` #[inline] #[stable(feature = "lazy_cell", since = "1.80.0")] pub fn force(this: &LazyLock) -> &T { this.once.call_once_force(|state| { if state.is_poisoned() { panic_poisoned(); } // SAFETY: `call_once` only runs this closure once, ever. let data = unsafe { &mut *this.data.get() }; let f = unsafe { ManuallyDrop::take(&mut data.f) }; let value = f(); data.value = ManuallyDrop::new(value); }); // SAFETY: // There are four possible scenarios: // * the closure was called and initialized `value`. // * the closure was called and panicked, so this point is never reached. // * the closure was not called, but a previous call initialized `value`. // * the closure was not called because the Once is poisoned, which we handled above. // So `value` has definitely been initialized and will not be modified again. unsafe { &*(*this.data.get()).value } } } impl LazyLock { /// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or /// poisoned), returns `None`. /// /// # Examples /// /// ``` /// #![feature(lazy_get)] /// /// use std::sync::LazyLock; /// /// let mut lazy = LazyLock::new(|| 92); /// /// assert_eq!(LazyLock::get_mut(&mut lazy), None); /// let _ = LazyLock::force(&lazy); /// *LazyLock::get_mut(&mut lazy).unwrap() = 44; /// assert_eq!(*lazy, 44); /// ``` #[inline] #[unstable(feature = "lazy_get", issue = "129333")] pub fn get_mut(this: &mut LazyLock) -> Option<&mut T> { // `state()` does not perform an atomic load, so prefer it over `is_complete()`. let state = this.once.state(); match state { // SAFETY: // The closure has been run successfully, so `value` has been initialized. ExclusiveState::Complete => Some(unsafe { &mut this.data.get_mut().value }), _ => None, } } /// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned), /// returns `None`. /// /// # Examples /// /// ``` /// #![feature(lazy_get)] /// /// use std::sync::LazyLock; /// /// let lazy = LazyLock::new(|| 92); /// /// assert_eq!(LazyLock::get(&lazy), None); /// let _ = LazyLock::force(&lazy); /// assert_eq!(LazyLock::get(&lazy), Some(&92)); /// ``` #[inline] #[unstable(feature = "lazy_get", issue = "129333")] pub fn get(this: &LazyLock) -> Option<&T> { if this.once.is_completed() { // SAFETY: // The closure has been run successfully, so `value` has been initialized // and will not be modified again. Some(unsafe { &(*this.data.get()).value }) } else { None } } } #[stable(feature = "lazy_cell", since = "1.80.0")] impl Drop for LazyLock { fn drop(&mut self) { match self.once.state() { ExclusiveState::Incomplete => unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) }, ExclusiveState::Complete => unsafe { ManuallyDrop::drop(&mut self.data.get_mut().value) }, ExclusiveState::Poisoned => {} } } } #[stable(feature = "lazy_cell", since = "1.80.0")] impl T> Deref for LazyLock { type Target = T; /// Dereferences the value. /// /// This method will block the calling thread if another initialization /// routine is currently running. /// /// # Panics /// /// If the initialization closure panics (the one that is passed to the [`new()`] method), the /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future /// accesses of the lock (via [`force()`] or a dereference) to panic. /// /// [`new()`]: LazyLock::new /// [`force()`]: LazyLock::force #[inline] fn deref(&self) -> &T { LazyLock::force(self) } } #[stable(feature = "lazy_deref_mut", since = "1.89.0")] impl T> DerefMut for LazyLock { /// # Panics /// /// If the initialization closure panics (the one that is passed to the [`new()`] method), the /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future /// accesses of the lock (via [`force()`] or a dereference) to panic. /// /// [`new()`]: LazyLock::new /// [`force()`]: LazyLock::force #[inline] fn deref_mut(&mut self) -> &mut T { LazyLock::force_mut(self) } } #[stable(feature = "lazy_cell", since = "1.80.0")] impl Default for LazyLock { /// Creates a new lazy value using `Default` as the initializing function. #[inline] fn default() -> LazyLock { LazyLock::new(T::default) } } #[stable(feature = "lazy_cell", since = "1.80.0")] impl fmt::Debug for LazyLock { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut d = f.debug_tuple("LazyLock"); match LazyLock::get(self) { Some(v) => d.field(v), None => d.field(&format_args!("")), }; d.finish() } } #[cold] #[inline(never)] fn panic_poisoned() -> ! { panic!("LazyLock instance has previously been poisoned") } // We never create a `&F` from a `&LazyLock` so it is fine // to not impl `Sync` for `F`. #[stable(feature = "lazy_cell", since = "1.80.0")] unsafe impl Sync for LazyLock {} // auto-derived `Send` impl is OK. #[stable(feature = "lazy_cell", since = "1.80.0")] impl RefUnwindSafe for LazyLock {} #[stable(feature = "lazy_cell", since = "1.80.0")] impl UnwindSafe for LazyLock {}