| 1 | use super::once::OnceExclusiveState; |
| 2 | use crate::cell::UnsafeCell; |
| 3 | use crate::mem::ManuallyDrop; |
| 4 | use crate::ops::{Deref, DerefMut}; |
| 5 | use crate::panic::{RefUnwindSafe, UnwindSafe}; |
| 6 | use crate::sync::Once; |
| 7 | use crate::{fmt, ptr}; |
| 8 | |
| 9 | // We use the state of a Once as discriminant value. Upon creation, the state is |
| 10 | // "incomplete" and `f` contains the initialization closure. In the first call to |
| 11 | // `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state |
| 12 | // is changed to "complete". If it panics, the Once is poisoned, so none of the |
| 13 | // two fields is initialized. |
| 14 | union Data<T, F> { |
| 15 | value: ManuallyDrop<T>, |
| 16 | f: ManuallyDrop<F>, |
| 17 | } |
| 18 | |
| 19 | /// A value which is initialized on the first access. |
| 20 | /// |
| 21 | /// This type is a thread-safe [`LazyCell`], and can be used in statics. |
| 22 | /// Since initialization may be called from multiple threads, any |
| 23 | /// dereferencing call will block the calling thread if another |
| 24 | /// initialization routine is currently running. |
| 25 | /// |
| 26 | /// [`LazyCell`]: crate::cell::LazyCell |
| 27 | /// |
| 28 | /// # Poisoning |
| 29 | /// |
| 30 | /// If the initialization closure passed to [`LazyLock::new`] panics, the lock will be poisoned. |
| 31 | /// Once the lock is poisoned, any threads that attempt to access this lock (via a dereference |
| 32 | /// or via an explicit call to [`force()`]) will panic. |
| 33 | /// |
| 34 | /// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key |
| 35 | /// difference, however, is that poisoning in `LazyLock` is _unrecoverable_. All future accesses of |
| 36 | /// the lock from other threads will panic, whereas a type in [`std::sync::poison`] like |
| 37 | /// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`]. |
| 38 | /// |
| 39 | /// [`force()`]: LazyLock::force |
| 40 | /// [`std::sync::poison`]: crate::sync::poison |
| 41 | /// [`std::sync::poison::Mutex`]: crate::sync::poison::Mutex |
| 42 | /// [`PoisonError::into_inner()`]: crate::sync::poison::PoisonError::into_inner |
| 43 | /// |
| 44 | /// # Examples |
| 45 | /// |
| 46 | /// Initialize static variables with `LazyLock`. |
| 47 | /// ``` |
| 48 | /// use std::sync::LazyLock; |
| 49 | /// |
| 50 | /// // Note: static items do not call [`Drop`] on program termination, so this won't be deallocated. |
| 51 | /// // this is fine, as the OS can deallocate the terminated program faster than we can free memory |
| 52 | /// // but tools like valgrind might report "memory leaks" as it isn't obvious this is intentional. |
| 53 | /// static DEEP_THOUGHT: LazyLock<String> = LazyLock::new(|| { |
| 54 | /// # mod another_crate { |
| 55 | /// # pub fn great_question() -> String { "42" .to_string() } |
| 56 | /// # } |
| 57 | /// // M3 Ultra takes about 16 million years in --release config |
| 58 | /// another_crate::great_question() |
| 59 | /// }); |
| 60 | /// |
| 61 | /// // The `String` is built, stored in the `LazyLock`, and returned as `&String`. |
| 62 | /// let _ = &*DEEP_THOUGHT; |
| 63 | /// ``` |
| 64 | /// |
| 65 | /// Initialize fields with `LazyLock`. |
| 66 | /// ``` |
| 67 | /// use std::sync::LazyLock; |
| 68 | /// |
| 69 | /// #[derive(Debug)] |
| 70 | /// struct UseCellLock { |
| 71 | /// number: LazyLock<u32>, |
| 72 | /// } |
| 73 | /// fn main() { |
| 74 | /// let lock: LazyLock<u32> = LazyLock::new(|| 0u32); |
| 75 | /// |
| 76 | /// let data = UseCellLock { number: lock }; |
| 77 | /// println!("{}" , *data.number); |
| 78 | /// } |
| 79 | /// ``` |
| 80 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 81 | pub struct LazyLock<T, F = fn() -> T> { |
| 82 | // FIXME(nonpoison_once): if possible, switch to nonpoison version once it is available |
| 83 | once: Once, |
| 84 | data: UnsafeCell<Data<T, F>>, |
| 85 | } |
| 86 | |
| 87 | impl<T, F: FnOnce() -> T> LazyLock<T, F> { |
| 88 | /// Creates a new lazy value with the given initializing function. |
| 89 | /// |
| 90 | /// # Examples |
| 91 | /// |
| 92 | /// ``` |
| 93 | /// use std::sync::LazyLock; |
| 94 | /// |
| 95 | /// let hello = "Hello, World!" .to_string(); |
| 96 | /// |
| 97 | /// let lazy = LazyLock::new(|| hello.to_uppercase()); |
| 98 | /// |
| 99 | /// assert_eq!(&*lazy, "HELLO, WORLD!" ); |
| 100 | /// ``` |
| 101 | #[inline ] |
| 102 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 103 | #[rustc_const_stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 104 | pub const fn new(f: F) -> LazyLock<T, F> { |
| 105 | LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) } |
| 106 | } |
| 107 | |
| 108 | /// Creates a new lazy value that is already initialized. |
| 109 | #[inline ] |
| 110 | #[cfg (test)] |
| 111 | pub(crate) fn preinit(value: T) -> LazyLock<T, F> { |
| 112 | let once = Once::new(); |
| 113 | once.call_once(|| {}); |
| 114 | LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) } |
| 115 | } |
| 116 | |
| 117 | /// Consumes this `LazyLock` returning the stored value. |
| 118 | /// |
| 119 | /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. |
| 120 | /// |
| 121 | /// # Panics |
| 122 | /// |
| 123 | /// Panics if the lock is poisoned. |
| 124 | /// |
| 125 | /// # Examples |
| 126 | /// |
| 127 | /// ``` |
| 128 | /// #![feature(lazy_cell_into_inner)] |
| 129 | /// |
| 130 | /// use std::sync::LazyLock; |
| 131 | /// |
| 132 | /// let hello = "Hello, World!" .to_string(); |
| 133 | /// |
| 134 | /// let lazy = LazyLock::new(|| hello.to_uppercase()); |
| 135 | /// |
| 136 | /// assert_eq!(&*lazy, "HELLO, WORLD!" ); |
| 137 | /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!" .to_string())); |
| 138 | /// ``` |
| 139 | #[unstable (feature = "lazy_cell_into_inner" , issue = "125623" )] |
| 140 | pub fn into_inner(mut this: Self) -> Result<T, F> { |
| 141 | let state = this.once.state(); |
| 142 | match state { |
| 143 | OnceExclusiveState::Poisoned => panic_poisoned(), |
| 144 | state => { |
| 145 | let this = ManuallyDrop::new(this); |
| 146 | let data = unsafe { ptr::read(&this.data) }.into_inner(); |
| 147 | match state { |
| 148 | OnceExclusiveState::Incomplete => { |
| 149 | Err(ManuallyDrop::into_inner(unsafe { data.f })) |
| 150 | } |
| 151 | OnceExclusiveState::Complete => { |
| 152 | Ok(ManuallyDrop::into_inner(unsafe { data.value })) |
| 153 | } |
| 154 | OnceExclusiveState::Poisoned => unreachable!(), |
| 155 | } |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | /// Forces the evaluation of this lazy value and returns a mutable reference to |
| 161 | /// the result. |
| 162 | /// |
| 163 | /// # Panics |
| 164 | /// |
| 165 | /// If the initialization closure panics (the one that is passed to the [`new()`] method), the |
| 166 | /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future |
| 167 | /// accesses of the lock (via [`force()`] or a dereference) to panic. |
| 168 | /// |
| 169 | /// [`new()`]: LazyLock::new |
| 170 | /// [`force()`]: LazyLock::force |
| 171 | /// |
| 172 | /// # Examples |
| 173 | /// |
| 174 | /// ``` |
| 175 | /// use std::sync::LazyLock; |
| 176 | /// |
| 177 | /// let mut lazy = LazyLock::new(|| 92); |
| 178 | /// |
| 179 | /// let p = LazyLock::force_mut(&mut lazy); |
| 180 | /// assert_eq!(*p, 92); |
| 181 | /// *p = 44; |
| 182 | /// assert_eq!(*lazy, 44); |
| 183 | /// ``` |
| 184 | #[inline ] |
| 185 | #[stable (feature = "lazy_get" , since = "1.94.0" )] |
| 186 | pub fn force_mut(this: &mut LazyLock<T, F>) -> &mut T { |
| 187 | #[cold ] |
| 188 | /// # Safety |
| 189 | /// May only be called when the state is `Incomplete`. |
| 190 | unsafe fn really_init_mut<T, F: FnOnce() -> T>(this: &mut LazyLock<T, F>) -> &mut T { |
| 191 | struct PoisonOnPanic<'a, T, F>(&'a mut LazyLock<T, F>); |
| 192 | impl<T, F> Drop for PoisonOnPanic<'_, T, F> { |
| 193 | #[inline ] |
| 194 | fn drop(&mut self) { |
| 195 | self.0.once.set_state(OnceExclusiveState::Poisoned); |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | // SAFETY: We always poison if the initializer panics (then we never check the data), |
| 200 | // or set the data on success. |
| 201 | let f = unsafe { ManuallyDrop::take(&mut this.data.get_mut().f) }; |
| 202 | // INVARIANT: Initiated from mutable reference, don't drop because we read it. |
| 203 | let guard = PoisonOnPanic(this); |
| 204 | let data = f(); |
| 205 | guard.0.data.get_mut().value = ManuallyDrop::new(data); |
| 206 | guard.0.once.set_state(OnceExclusiveState::Complete); |
| 207 | core::mem::forget(guard); |
| 208 | // SAFETY: We put the value there above. |
| 209 | unsafe { &mut this.data.get_mut().value } |
| 210 | } |
| 211 | |
| 212 | let state = this.once.state(); |
| 213 | match state { |
| 214 | OnceExclusiveState::Poisoned => panic_poisoned(), |
| 215 | // SAFETY: The `Once` states we completed the initialization. |
| 216 | OnceExclusiveState::Complete => unsafe { &mut this.data.get_mut().value }, |
| 217 | // SAFETY: The state is `Incomplete`. |
| 218 | OnceExclusiveState::Incomplete => unsafe { really_init_mut(this) }, |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | /// Forces the evaluation of this lazy value and returns a reference to |
| 223 | /// result. This is equivalent to the `Deref` impl, but is explicit. |
| 224 | /// |
| 225 | /// This method will block the calling thread if another initialization |
| 226 | /// routine is currently running. |
| 227 | /// |
| 228 | /// # Panics |
| 229 | /// |
| 230 | /// If the initialization closure panics (the one that is passed to the [`new()`] method), the |
| 231 | /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future |
| 232 | /// accesses of the lock (via [`force()`] or a dereference) to panic. |
| 233 | /// |
| 234 | /// [`new()`]: LazyLock::new |
| 235 | /// [`force()`]: LazyLock::force |
| 236 | /// |
| 237 | /// # Examples |
| 238 | /// |
| 239 | /// ``` |
| 240 | /// use std::sync::LazyLock; |
| 241 | /// |
| 242 | /// let lazy = LazyLock::new(|| 92); |
| 243 | /// |
| 244 | /// assert_eq!(LazyLock::force(&lazy), &92); |
| 245 | /// assert_eq!(&*lazy, &92); |
| 246 | /// ``` |
| 247 | #[inline ] |
| 248 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 249 | #[rustc_should_not_be_called_on_const_items] |
| 250 | pub fn force(this: &LazyLock<T, F>) -> &T { |
| 251 | this.once.call_once_force(|state| { |
| 252 | if state.is_poisoned() { |
| 253 | panic_poisoned(); |
| 254 | } |
| 255 | |
| 256 | // SAFETY: `call_once` only runs this closure once, ever. |
| 257 | let data = unsafe { &mut *this.data.get() }; |
| 258 | let f = unsafe { ManuallyDrop::take(&mut data.f) }; |
| 259 | let value = f(); |
| 260 | data.value = ManuallyDrop::new(value); |
| 261 | }); |
| 262 | |
| 263 | // SAFETY: |
| 264 | // There are four possible scenarios: |
| 265 | // * the closure was called and initialized `value`. |
| 266 | // * the closure was called and panicked, so this point is never reached. |
| 267 | // * the closure was not called, but a previous call initialized `value`. |
| 268 | // * the closure was not called because the Once is poisoned, which we handled above. |
| 269 | // So `value` has definitely been initialized and will not be modified again. |
| 270 | unsafe { &*(*this.data.get()).value } |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | impl<T, F> LazyLock<T, F> { |
| 275 | /// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or |
| 276 | /// poisoned), returns `None`. |
| 277 | /// |
| 278 | /// # Examples |
| 279 | /// |
| 280 | /// ``` |
| 281 | /// use std::sync::LazyLock; |
| 282 | /// |
| 283 | /// let mut lazy = LazyLock::new(|| 92); |
| 284 | /// |
| 285 | /// assert_eq!(LazyLock::get_mut(&mut lazy), None); |
| 286 | /// let _ = LazyLock::force(&lazy); |
| 287 | /// *LazyLock::get_mut(&mut lazy).unwrap() = 44; |
| 288 | /// assert_eq!(*lazy, 44); |
| 289 | /// ``` |
| 290 | #[inline ] |
| 291 | #[stable (feature = "lazy_get" , since = "1.94.0" )] |
| 292 | pub fn get_mut(this: &mut LazyLock<T, F>) -> Option<&mut T> { |
| 293 | // `state()` does not perform an atomic load, so prefer it over `is_complete()`. |
| 294 | let state = this.once.state(); |
| 295 | match state { |
| 296 | // SAFETY: |
| 297 | // The closure has been run successfully, so `value` has been initialized. |
| 298 | OnceExclusiveState::Complete => Some(unsafe { &mut this.data.get_mut().value }), |
| 299 | _ => None, |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | /// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned), |
| 304 | /// returns `None`. |
| 305 | /// |
| 306 | /// # Examples |
| 307 | /// |
| 308 | /// ``` |
| 309 | /// use std::sync::LazyLock; |
| 310 | /// |
| 311 | /// let lazy = LazyLock::new(|| 92); |
| 312 | /// |
| 313 | /// assert_eq!(LazyLock::get(&lazy), None); |
| 314 | /// let _ = LazyLock::force(&lazy); |
| 315 | /// assert_eq!(LazyLock::get(&lazy), Some(&92)); |
| 316 | /// ``` |
| 317 | #[inline ] |
| 318 | #[stable (feature = "lazy_get" , since = "1.94.0" )] |
| 319 | #[rustc_should_not_be_called_on_const_items] |
| 320 | pub fn get(this: &LazyLock<T, F>) -> Option<&T> { |
| 321 | if this.once.is_completed() { |
| 322 | // SAFETY: |
| 323 | // The closure has been run successfully, so `value` has been initialized |
| 324 | // and will not be modified again. |
| 325 | Some(unsafe { &(*this.data.get()).value }) |
| 326 | } else { |
| 327 | None |
| 328 | } |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 333 | impl<T, F> Drop for LazyLock<T, F> { |
| 334 | fn drop(&mut self) { |
| 335 | match self.once.state() { |
| 336 | OnceExclusiveState::Incomplete => unsafe { |
| 337 | ManuallyDrop::drop(&mut self.data.get_mut().f) |
| 338 | }, |
| 339 | OnceExclusiveState::Complete => unsafe { |
| 340 | ManuallyDrop::drop(&mut self.data.get_mut().value) |
| 341 | }, |
| 342 | OnceExclusiveState::Poisoned => {} |
| 343 | } |
| 344 | } |
| 345 | } |
| 346 | |
| 347 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 348 | impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> { |
| 349 | type Target = T; |
| 350 | |
| 351 | /// Dereferences the value. |
| 352 | /// |
| 353 | /// This method will block the calling thread if another initialization |
| 354 | /// routine is currently running. |
| 355 | /// |
| 356 | /// # Panics |
| 357 | /// |
| 358 | /// If the initialization closure panics (the one that is passed to the [`new()`] method), the |
| 359 | /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future |
| 360 | /// accesses of the lock (via [`force()`] or a dereference) to panic. |
| 361 | /// |
| 362 | /// [`new()`]: LazyLock::new |
| 363 | /// [`force()`]: LazyLock::force |
| 364 | #[inline ] |
| 365 | fn deref(&self) -> &T { |
| 366 | LazyLock::force(self) |
| 367 | } |
| 368 | } |
| 369 | |
| 370 | #[stable (feature = "lazy_deref_mut" , since = "1.89.0" )] |
| 371 | impl<T, F: FnOnce() -> T> DerefMut for LazyLock<T, F> { |
| 372 | /// # Panics |
| 373 | /// |
| 374 | /// If the initialization closure panics (the one that is passed to the [`new()`] method), the |
| 375 | /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future |
| 376 | /// accesses of the lock (via [`force()`] or a dereference) to panic. |
| 377 | /// |
| 378 | /// [`new()`]: LazyLock::new |
| 379 | /// [`force()`]: LazyLock::force |
| 380 | #[inline ] |
| 381 | fn deref_mut(&mut self) -> &mut T { |
| 382 | LazyLock::force_mut(self) |
| 383 | } |
| 384 | } |
| 385 | |
| 386 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 387 | impl<T: Default> Default for LazyLock<T> { |
| 388 | /// Creates a new lazy value using `Default` as the initializing function. |
| 389 | #[inline ] |
| 390 | fn default() -> LazyLock<T> { |
| 391 | LazyLock::new(T::default) |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 396 | impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> { |
| 397 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 398 | let mut d = f.debug_tuple("LazyLock" ); |
| 399 | match LazyLock::get(self) { |
| 400 | Some(v) => d.field(v), |
| 401 | None => d.field(&format_args!("<uninit>" )), |
| 402 | }; |
| 403 | d.finish() |
| 404 | } |
| 405 | } |
| 406 | |
| 407 | #[cold ] |
| 408 | #[inline (never)] |
| 409 | fn panic_poisoned() -> ! { |
| 410 | panic!("LazyLock instance has previously been poisoned" ) |
| 411 | } |
| 412 | |
| 413 | // We never create a `&F` from a `&LazyLock<T, F>` so it is fine |
| 414 | // to not impl `Sync` for `F`. |
| 415 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 416 | unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {} |
| 417 | // auto-derived `Send` impl is OK. |
| 418 | |
| 419 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 420 | impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> {} |
| 421 | #[stable (feature = "lazy_cell" , since = "1.80.0" )] |
| 422 | impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F> {} |
| 423 | |