1 | use super::UnsafeCell; |
2 | use crate::hint::unreachable_unchecked; |
3 | use crate::ops::{Deref, DerefMut}; |
4 | use crate::{fmt, mem}; |
5 | |
6 | enum 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" )] |
38 | pub struct LazyCell<T, F = fn() -> T> { |
39 | state: UnsafeCell<State<T, F>>, |
40 | } |
41 | |
42 | impl<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 | |
221 | impl<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" )] |
279 | impl<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_deref_mut" , since = "CURRENT_RUSTC_VERSION" )] |
288 | impl<T, F: FnOnce() -> T> DerefMut for LazyCell<T, F> { |
289 | #[inline ] |
290 | fn deref_mut(&mut self) -> &mut T { |
291 | LazyCell::force_mut(self) |
292 | } |
293 | } |
294 | |
295 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
296 | impl<T: Default> Default for LazyCell<T> { |
297 | /// Creates a new lazy value using `Default` as the initializing function. |
298 | #[inline ] |
299 | fn default() -> LazyCell<T> { |
300 | LazyCell::new(T::default) |
301 | } |
302 | } |
303 | |
304 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
305 | impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> { |
306 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
307 | let mut d: DebugTuple<'_, '_> = f.debug_tuple(name:"LazyCell" ); |
308 | match LazyCell::get(self) { |
309 | Some(data: &T) => d.field(data), |
310 | None => d.field(&format_args!("<uninit>" )), |
311 | }; |
312 | d.finish() |
313 | } |
314 | } |
315 | |
316 | #[cold ] |
317 | #[inline (never)] |
318 | const fn panic_poisoned() -> ! { |
319 | panic!("LazyCell instance has previously been poisoned" ) |
320 | } |
321 | |