lazy.rs - source
Description: Source of the Rust file `library/core/src/cell/lazy.rs`.

#
core/cell/
lazy.rs

    1use super::UnsafeCell;
    2use crate::hint::unreachable_unchecked;
    3use crate::ops::{Deref, DerefMut};
    4use crate::{fmt, mem};
    5
    6enum State<T, F> {
    7    Uninit(F),
    8    Init(T),
    9    Poisoned,
    10}
    11
    12/// A value which is initialized on the first access.
    13///
    14/// For a thread-safe version of this struct, see [`std::sync::LazyLock`].
    15///
    16/// [`std::sync::LazyLock`]: ../../std/sync/struct.LazyLock.html
    17///
    18/// # Poisoning
    19///
    20/// If the initialization closure passed to [`LazyCell::new`] panics, the cell will be poisoned.
    21/// Once the cell is poisoned, any threads that attempt to access this cell (via a dereference
    22/// or via an explicit call to [`force()`]) will panic.
    23///
    24/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key
    25/// difference, however, is that poisoning in `LazyCell` is _unrecoverable_. All future accesses of
    26/// the cell from other threads will panic, whereas a type in [`std::sync::poison`] like
    27/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`].
    28///
    29/// [`force()`]: LazyCell::force
    30/// [`std::sync::poison`]: ../../std/sync/poison/index.html
    31/// [`std::sync::poison::Mutex`]: ../../std/sync/poison/struct.Mutex.html
    32/// [`PoisonError::into_inner()`]: ../../std/sync/poison/struct.PoisonError.html#method.into_inner
    33///
    34/// # Examples
    35///
    36/// ```
    37/// use std::cell::LazyCell;
    38///
    39/// let lazy: LazyCell<i32> = LazyCell::new(|| {
    40///     println!("initializing");
    41///     92
    42/// });
    43/// println!("ready");
    44/// println!("{}", *lazy);
    45/// println!("{}", *lazy);
    46///
    47/// // Prints:
    48/// //   ready
    49/// //   initializing
    50/// //   92
    51/// //   92
    52/// ```
    53#[stable(feature = "lazy_cell", since = "1.80.0")]
    54pub struct LazyCell<T, F = fn() -> T> {
    55    state: UnsafeCell<State<T, F>>,
    56}
    57
    58impl<T, F: FnOnce() -> T> LazyCell<T, F> {
    59    /// Creates a new lazy value with the given initializing function.
    60    ///
    61    /// # Examples
    62    ///
    63    /// ```
    64    /// use std::cell::LazyCell;
    65    ///
    66    /// let hello = "Hello, World!".to_string();
    67    ///
    68    /// let lazy = LazyCell::new(|| hello.to_uppercase());
    69    ///
    70    /// assert_eq!(&*lazy, "HELLO, WORLD!");
    71    /// ```
    72    #[inline]
    73    #[stable(feature = "lazy_cell", since = "1.80.0")]
    74    #[rustc_const_stable(feature = "lazy_cell", since = "1.80.0")]
    75    pub const fn new(f: F) -> LazyCell<T, F> {
    76        LazyCell { state: UnsafeCell::new(State::Uninit(f)) }
    77    }
    78
    79    /// Consumes this `LazyCell` returning the stored value.
    80    ///
    81    /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
    82    ///
    83    /// # Panics
    84    ///
    85    /// Panics if the cell is poisoned.
    86    ///
    87    /// # Examples
    88    ///
    89    /// ```
    90    /// #![feature(lazy_cell_into_inner)]
    91    ///
    92    /// use std::cell::LazyCell;
    93    ///
    94    /// let hello = "Hello, World!".to_string();
    95    ///
    96    /// let lazy = LazyCell::new(|| hello.to_uppercase());
    97    ///
    98    /// assert_eq!(&*lazy, "HELLO, WORLD!");
    99    /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
    100    /// ```
    101    #[unstable(feature = "lazy_cell_into_inner", issue = "125623")]
    102    #[rustc_const_unstable(feature = "lazy_cell_into_inner", issue = "125623")]
    103    pub const fn into_inner(this: Self) -> Result<T, F> {
    104        match this.state.into_inner() {
    105            State::Init(data) => Ok(data),
    106            State::Uninit(f) => Err(f),
    107            State::Poisoned => panic_poisoned(),
    108        }
    109    }
    110
    111    /// Forces the evaluation of this lazy value and returns a reference to
    112    /// the result.
    113    ///
    114    /// This is equivalent to the `Deref` impl, but is explicit.
    115    ///
    116    /// # Panics
    117    ///
    118    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
    119    /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
    120    /// accesses of the cell (via [`force()`] or a dereference) to panic.
    121    ///
    122    /// [`new()`]: LazyCell::new
    123    /// [`force()`]: LazyCell::force
    124    ///
    125    /// # Examples
    126    ///
    127    /// ```
    128    /// use std::cell::LazyCell;
    129    ///
    130    /// let lazy = LazyCell::new(|| 92);
    131    ///
    132    /// assert_eq!(LazyCell::force(&lazy), &92);
    133    /// assert_eq!(&*lazy, &92);
    134    /// ```
    135    #[inline]
    136    #[stable(feature = "lazy_cell", since = "1.80.0")]
    137    #[rustc_should_not_be_called_on_const_items]
    138    pub fn force(this: &LazyCell<T, F>) -> &T {
    139        // SAFETY:
    140        // This invalidates any mutable references to the data. The resulting
    141        // reference lives either until the end of the borrow of `this` (in the
    142        // initialized case) or is invalidated in `really_init` (in the
    143        // uninitialized case; `really_init` will create and return a fresh reference).
    144        let state = unsafe { &*this.state.get() };
    145        match state {
    146            State::Init(data) => data,
    147            // SAFETY: The state is uninitialized.
    148            State::Uninit(_) => unsafe { LazyCell::really_init(this) },
    149            State::Poisoned => panic_poisoned(),
    150        }
    151    }
    152
    153    /// Forces the evaluation of this lazy value and returns a mutable reference to
    154    /// the result.
    155    ///
    156    /// # Panics
    157    ///
    158    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
    159    /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
    160    /// accesses of the cell (via [`force()`] or a dereference) to panic.
    161    ///
    162    /// [`new()`]: LazyCell::new
    163    /// [`force()`]: LazyCell::force
    164    ///
    165    /// # Examples
    166    ///
    167    /// ```
    168    /// use std::cell::LazyCell;
    169    ///
    170    /// let mut lazy = LazyCell::new(|| 92);
    171    ///
    172    /// let p = LazyCell::force_mut(&mut lazy);
    173    /// assert_eq!(*p, 92);
    174    /// *p = 44;
    175    /// assert_eq!(*lazy, 44);
    176    /// ```
    177    #[inline]
    178    #[stable(feature = "lazy_get", since = "1.94.0")]
    179    pub fn force_mut(this: &mut LazyCell<T, F>) -> &mut T {
    180        #[cold]
    181        /// # Safety
    182        /// May only be called when the state is `Uninit`.
    183        unsafe fn really_init_mut<T, F: FnOnce() -> T>(state: &mut State<T, F>) -> &mut T {
    184            // INVARIANT: Always valid, but the value may not be dropped.
    185            struct PoisonOnPanic<T, F>(*mut State<T, F>);
    186            impl<T, F> Drop for PoisonOnPanic<T, F> {
    187                #[inline]
    188                fn drop(&mut self) {
    189                    // SAFETY: Invariant states it is valid, and we don't drop the old value.
    190                    unsafe {
    191                        self.0.write(State::Poisoned);
    192                    }
    193                }
    194            }
    195
    196            let State::Uninit(f) = state else {
    197                // `unreachable!()` here won't optimize out because the function is cold.
    198                // SAFETY: Precondition.
    199                unsafe { unreachable_unchecked() };
    200            };
    201            // SAFETY: We never drop the state after we read `f`, and we write a valid value back
    202            // in any case, panic or success. `f` can't access the `LazyCell` because it is mutably
    203            // borrowed.
    204            let f = unsafe { core::ptr::read(f) };
    205            // INVARIANT: Initiated from mutable reference, don't drop because we read it.
    206            let guard = PoisonOnPanic(state);
    207            let data = f();
    208            // SAFETY: `PoisonOnPanic` invariant, and we don't drop the old value.
    209            unsafe {
    210                core::ptr::write(guard.0, State::Init(data));
    211            }
    212            core::mem::forget(guard);
    213            let State::Init(data) = state else { unreachable!() };
    214            data
    215        }
    216
    217        let state = this.state.get_mut();
    218        match state {
    219            State::Init(data) => data,
    220            // SAFETY: `state` is `Uninit`.
    221            State::Uninit(_) => unsafe { really_init_mut(state) },
    222            State::Poisoned => panic_poisoned(),
    223        }
    224    }
    225
    226    /// # Safety
    227    /// May only be called when the state is `Uninit`.
    228    #[cold]
    229    unsafe fn really_init(this: &LazyCell<T, F>) -> &T {
    230        // SAFETY:
    231        // This function is only called when the state is uninitialized,
    232        // so no references to `state` can exist except for the reference
    233        // in `force`, which is invalidated here and not accessed again.
    234        let state = unsafe { &mut *this.state.get() };
    235        // Temporarily mark the state as poisoned. This prevents reentrant
    236        // accesses and correctly poisons the cell if the closure panicked.
    237        let State::Uninit(f) = mem::replace(state, State::Poisoned) else { unreachable!() };
    238
    239        let data = f();
    240
    241        // SAFETY:
    242        // If the closure accessed the cell through something like a reentrant
    243        // mutex, but caught the panic resulting from the state being poisoned,
    244        // the mutable borrow for `state` will be invalidated, so we need to
    245        // go through the `UnsafeCell` pointer here. The state can only be
    246        // poisoned at this point, so using `write` to skip the destructor
    247        // of `State` should help the optimizer.
    248        unsafe { this.state.get().write(State::Init(data)) };
    249
    250        // SAFETY:
    251        // The previous references were invalidated by the `write` call above,
    252        // so do a new shared borrow of the state instead.
    253        let state = unsafe { &*this.state.get() };
    254        let State::Init(data) = state else { unreachable!() };
    255        data
    256    }
    257}
    258
    259impl<T, F> LazyCell<T, F> {
    260    /// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or
    261    /// poisoned), returns `None`.
    262    ///
    263    /// # Examples
    264    ///
    265    /// ```
    266    /// use std::cell::LazyCell;
    267    ///
    268    /// let mut lazy = LazyCell::new(|| 92);
    269    ///
    270    /// assert_eq!(LazyCell::get_mut(&mut lazy), None);
    271    /// let _ = LazyCell::force(&lazy);
    272    /// *LazyCell::get_mut(&mut lazy).unwrap() = 44;
    273    /// assert_eq!(*lazy, 44);
    274    /// ```
    275    #[inline]
    276    #[stable(feature = "lazy_get", since = "1.94.0")]
    277    pub fn get_mut(this: &mut LazyCell<T, F>) -> Option<&mut T> {
    278        let state = this.state.get_mut();
    279        match state {
    280            State::Init(data) => Some(data),
    281            _ => None,
    282        }
    283    }
    284
    285    /// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned),
    286    /// returns `None`.
    287    ///
    288    /// # Examples
    289    ///
    290    /// ```
    291    /// use std::cell::LazyCell;
    292    ///
    293    /// let lazy = LazyCell::new(|| 92);
    294    ///
    295    /// assert_eq!(LazyCell::get(&lazy), None);
    296    /// let _ = LazyCell::force(&lazy);
    297    /// assert_eq!(LazyCell::get(&lazy), Some(&92));
    298    /// ```
    299    #[inline]
    300    #[stable(feature = "lazy_get", since = "1.94.0")]
    301    pub fn get(this: &LazyCell<T, F>) -> Option<&T> {
    302        // SAFETY:
    303        // This is sound for the same reason as in `force`: once the state is
    304        // initialized, it will not be mutably accessed again, so this reference
    305        // will stay valid for the duration of the borrow to `self`.
    306        let state = unsafe { &*this.state.get() };
    307        match state {
    308            State::Init(data) => Some(data),
    309            _ => None,
    310        }
    311    }
    312}
    313
    314#[stable(feature = "lazy_cell", since = "1.80.0")]
    315impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
    316    type Target = T;
    317
    318    /// # Panics
    319    ///
    320    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
    321    /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
    322    /// accesses of the cell (via [`force()`] or a dereference) to panic.
    323    ///
    324    /// [`new()`]: LazyCell::new
    325    /// [`force()`]: LazyCell::force
    326    #[inline]
    327    fn deref(&self) -> &T {
    328        LazyCell::force(self)
    329    }
    330}
    331
    332#[stable(feature = "lazy_deref_mut", since = "1.89.0")]
    333impl<T, F: FnOnce() -> T> DerefMut for LazyCell<T, F> {
    334    /// # Panics
    335    ///
    336    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
    337    /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
    338    /// accesses of the cell (via [`force()`] or a dereference) to panic.
    339    ///
    340    /// [`new()`]: LazyCell::new
    341    /// [`force()`]: LazyCell::force
    342    #[inline]
    343    fn deref_mut(&mut self) -> &mut T {
    344        LazyCell::force_mut(self)
    345    }
    346}
    347
    348#[stable(feature = "lazy_cell", since = "1.80.0")]
    349impl<T: Default> Default for LazyCell<T> {
    350    /// Creates a new lazy value using `Default` as the initializing function.
    351    #[inline]
    352    fn default() -> LazyCell<T> {
    353        LazyCell::new(T::default)
    354    }
    355}
    356
    357#[stable(feature = "lazy_cell", since = "1.80.0")]
    358impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> {
    359    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    360        let mut d = f.debug_tuple("LazyCell");
    361        match LazyCell::get(self) {
    362            Some(data) => d.field(data),
    363            None => d.field(&format_args!("<uninit>")),
    364        };
    365        d.finish()
    366    }
    367}
    368
    369#[cold]
    370#[inline(never)]
    371const fn panic_poisoned() -> ! {
    372    panic!("LazyCell instance has previously been poisoned")
    373}