Skip to main content

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