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 = "CURRENT_RUSTC_VERSION")]
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 = "CURRENT_RUSTC_VERSION")]
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 = "CURRENT_RUSTC_VERSION")]
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}