core/cell/
lazy.rs

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