| 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 | |