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}