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    pub fn force(this: &LazyCell<T, F>) -> &T {
138        // SAFETY:
139        // This invalidates any mutable references to the data. The resulting
140        // reference lives either until the end of the borrow of `this` (in the
141        // initialized case) or is invalidated in `really_init` (in the
142        // uninitialized case; `really_init` will create and return a fresh reference).
143        let state = unsafe { &*this.state.get() };
144        match state {
145            State::Init(data) => data,
146            // SAFETY: The state is uninitialized.
147            State::Uninit(_) => unsafe { LazyCell::really_init(this) },
148            State::Poisoned => panic_poisoned(),
149        }
150    }
151
152    /// Forces the evaluation of this lazy value and returns a mutable reference to
153    /// the result.
154    ///
155    /// # Panics
156    ///
157    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
158    /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
159    /// accesses of the cell (via [`force()`] or a dereference) to panic.
160    ///
161    /// [`new()`]: LazyCell::new
162    /// [`force()`]: LazyCell::force
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// #![feature(lazy_get)]
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    #[unstable(feature = "lazy_get", issue = "129333")]
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    /// #![feature(lazy_get)]
267    ///
268    /// use std::cell::LazyCell;
269    ///
270    /// let mut lazy = LazyCell::new(|| 92);
271    ///
272    /// assert_eq!(LazyCell::get_mut(&mut lazy), None);
273    /// let _ = LazyCell::force(&lazy);
274    /// *LazyCell::get_mut(&mut lazy).unwrap() = 44;
275    /// assert_eq!(*lazy, 44);
276    /// ```
277    #[inline]
278    #[unstable(feature = "lazy_get", issue = "129333")]
279    pub fn get_mut(this: &mut LazyCell<T, F>) -> Option<&mut T> {
280        let state = this.state.get_mut();
281        match state {
282            State::Init(data) => Some(data),
283            _ => None,
284        }
285    }
286
287    /// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned),
288    /// returns `None`.
289    ///
290    /// # Examples
291    ///
292    /// ```
293    /// #![feature(lazy_get)]
294    ///
295    /// use std::cell::LazyCell;
296    ///
297    /// let lazy = LazyCell::new(|| 92);
298    ///
299    /// assert_eq!(LazyCell::get(&lazy), None);
300    /// let _ = LazyCell::force(&lazy);
301    /// assert_eq!(LazyCell::get(&lazy), Some(&92));
302    /// ```
303    #[inline]
304    #[unstable(feature = "lazy_get", issue = "129333")]
305    pub fn get(this: &LazyCell<T, F>) -> Option<&T> {
306        // SAFETY:
307        // This is sound for the same reason as in `force`: once the state is
308        // initialized, it will not be mutably accessed again, so this reference
309        // will stay valid for the duration of the borrow to `self`.
310        let state = unsafe { &*this.state.get() };
311        match state {
312            State::Init(data) => Some(data),
313            _ => None,
314        }
315    }
316}
317
318#[stable(feature = "lazy_cell", since = "1.80.0")]
319impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
320    type Target = T;
321
322    /// # Panics
323    ///
324    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
325    /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
326    /// accesses of the cell (via [`force()`] or a dereference) to panic.
327    ///
328    /// [`new()`]: LazyCell::new
329    /// [`force()`]: LazyCell::force
330    #[inline]
331    fn deref(&self) -> &T {
332        LazyCell::force(self)
333    }
334}
335
336#[stable(feature = "lazy_deref_mut", since = "1.89.0")]
337impl<T, F: FnOnce() -> T> DerefMut for LazyCell<T, F> {
338    /// # Panics
339    ///
340    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
341    /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future
342    /// accesses of the cell (via [`force()`] or a dereference) to panic.
343    ///
344    /// [`new()`]: LazyCell::new
345    /// [`force()`]: LazyCell::force
346    #[inline]
347    fn deref_mut(&mut self) -> &mut T {
348        LazyCell::force_mut(self)
349    }
350}
351
352#[stable(feature = "lazy_cell", since = "1.80.0")]
353impl<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#[cold]
374#[inline(never)]
375const fn panic_poisoned() -> ! {
376    panic!("LazyCell instance has previously been poisoned")
377}