lazy.rs 18.1 KB
Newer Older
A
Ashley Mannix 已提交
1
//! Lazy values and one-time initialization of static data.
A
Aleksey Kladov 已提交
2

3 4 5
#[cfg(test)]
mod tests;

A
Aleksey Kladov 已提交
6 7 8
use crate::{
    cell::{Cell, UnsafeCell},
    fmt,
M
Mara Bos 已提交
9
    marker::PhantomData,
10
    mem::MaybeUninit,
A
Ashley Mannix 已提交
11
    ops::{Deref, Drop},
A
Aleksey Kladov 已提交
12
    panic::{RefUnwindSafe, UnwindSafe},
13
    pin::Pin,
14
    sync::Once,
A
Aleksey Kladov 已提交
15 16
};

A
Ashley Mannix 已提交
17
#[doc(inline)]
A
Ashley Mannix 已提交
18
#[unstable(feature = "once_cell", issue = "74465")]
A
Ashley Mannix 已提交
19
pub use core::lazy::*;
A
Aleksey Kladov 已提交
20

A
Ashley Mannix 已提交
21
/// A synchronization primitive which can be written to only once.
A
Aleksey Kladov 已提交
22
///
A
Ashley Mannix 已提交
23
/// This type is a thread-safe `OnceCell`.
A
Aleksey Kladov 已提交
24
///
A
Ashley Mannix 已提交
25
/// # Examples
A
Aleksey Kladov 已提交
26 27
///
/// ```
A
Ashley Mannix 已提交
28
/// #![feature(once_cell)]
A
Aleksey Kladov 已提交
29 30 31
///
/// use std::lazy::SyncOnceCell;
///
A
Ashley Mannix 已提交
32
/// static CELL: SyncOnceCell<String> = SyncOnceCell::new();
A
Aleksey Kladov 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45
/// assert!(CELL.get().is_none());
///
/// std::thread::spawn(|| {
///     let value: &String = CELL.get_or_init(|| {
///         "Hello, World!".to_string()
///     });
///     assert_eq!(value, "Hello, World!");
/// }).join().unwrap();
///
/// let value: Option<&String> = CELL.get();
/// assert!(value.is_some());
/// assert_eq!(value.unwrap().as_str(), "Hello, World!");
/// ```
A
Ashley Mannix 已提交
46
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
47
pub struct SyncOnceCell<T> {
48
    once: Once,
A
Ashley Mannix 已提交
49 50
    // Whether or not the value is initialized is tracked by `state_and_queue`.
    value: UnsafeCell<MaybeUninit<T>>,
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl.
    ///
    /// ```compile_fail,E0597
    /// #![feature(once_cell)]
    ///
    /// use std::lazy::SyncOnceCell;
    ///
    /// struct A<'a>(&'a str);
    ///
    /// impl<'a> Drop for A<'a> {
    ///     fn drop(&mut self) {}
    /// }
    ///
    /// let cell = SyncOnceCell::new();
    /// {
    ///     let s = String::new();
    ///     let _ = cell.set(A(&s));
    /// }
    /// ```
M
Mara Bos 已提交
70
    _marker: PhantomData<T>,
A
Aleksey Kladov 已提交
71 72 73
}

// Why do we need `T: Send`?
A
Ashley Mannix 已提交
74
// Thread A creates a `SyncOnceCell` and shares it with
A
Aleksey Kladov 已提交
75 76 77
// scoped thread B, which fills the cell, which is
// then destroyed by A. That is, destructor observes
// a sent value.
A
Ashley Mannix 已提交
78
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
79
unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {}
A
Ashley Mannix 已提交
80
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
81 82
unsafe impl<T: Send> Send for SyncOnceCell<T> {}

A
Ashley Mannix 已提交
83
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
84
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {}
A
Ashley Mannix 已提交
85
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
86 87
impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {}

A
Ashley Mannix 已提交
88
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
89 90 91 92 93 94
impl<T> Default for SyncOnceCell<T> {
    fn default() -> SyncOnceCell<T> {
        SyncOnceCell::new()
    }
}

A
Ashley Mannix 已提交
95
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
96 97 98
impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.get() {
A
Ashley Mannix 已提交
99 100
            Some(v) => f.debug_tuple("Once").field(v).finish(),
            None => f.write_str("Once(Uninit)"),
A
Aleksey Kladov 已提交
101 102 103 104
        }
    }
}

A
Ashley Mannix 已提交
105
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
106 107
impl<T: Clone> Clone for SyncOnceCell<T> {
    fn clone(&self) -> SyncOnceCell<T> {
A
Ashley Mannix 已提交
108
        let cell = Self::new();
A
Aleksey Kladov 已提交
109
        if let Some(value) = self.get() {
A
Ashley Mannix 已提交
110
            match cell.set(value.clone()) {
A
Aleksey Kladov 已提交
111 112 113 114
                Ok(()) => (),
                Err(_) => unreachable!(),
            }
        }
A
Ashley Mannix 已提交
115
        cell
A
Aleksey Kladov 已提交
116 117 118
    }
}

A
Ashley Mannix 已提交
119
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
120 121 122
impl<T> From<T> for SyncOnceCell<T> {
    fn from(value: T) -> Self {
        let cell = Self::new();
A
Ashley Mannix 已提交
123 124 125 126
        match cell.set(value) {
            Ok(()) => cell,
            Err(_) => unreachable!(),
        }
A
Aleksey Kladov 已提交
127 128 129
    }
}

A
Ashley Mannix 已提交
130
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
131 132 133 134 135 136
impl<T: PartialEq> PartialEq for SyncOnceCell<T> {
    fn eq(&self, other: &SyncOnceCell<T>) -> bool {
        self.get() == other.get()
    }
}

A
Ashley Mannix 已提交
137
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
138 139 140 141
impl<T: Eq> Eq for SyncOnceCell<T> {}

impl<T> SyncOnceCell<T> {
    /// Creates a new empty cell.
A
Ashley Mannix 已提交
142
    #[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
143
    pub const fn new() -> SyncOnceCell<T> {
M
Mara Bos 已提交
144 145 146 147 148
        SyncOnceCell {
            once: Once::new(),
            value: UnsafeCell::new(MaybeUninit::uninit()),
            _marker: PhantomData,
        }
A
Aleksey Kladov 已提交
149 150 151 152 153 154
    }

    /// Gets the reference to the underlying value.
    ///
    /// Returns `None` if the cell is empty, or being initialized. This
    /// method never blocks.
A
Ashley Mannix 已提交
155
    #[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
156 157
    pub fn get(&self) -> Option<&T> {
        if self.is_initialized() {
158
            // Safe b/c checked is_initialized
A
Aleksey Kladov 已提交
159 160 161 162 163 164 165 166
            Some(unsafe { self.get_unchecked() })
        } else {
            None
        }
    }

    /// Gets the mutable reference to the underlying value.
    ///
A
Ashley Mannix 已提交
167
    /// Returns `None` if the cell is empty. This method never blocks.
A
Ashley Mannix 已提交
168
    #[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
169
    pub fn get_mut(&mut self) -> Option<&mut T> {
A
Ashley Mannix 已提交
170
        if self.is_initialized() {
171
            // Safe b/c checked is_initialized and we have a unique access
A
Ashley Mannix 已提交
172 173 174
            Some(unsafe { self.get_unchecked_mut() })
        } else {
            None
A
Aleksey Kladov 已提交
175 176 177 178 179
        }
    }

    /// Sets the contents of this cell to `value`.
    ///
180 181 182 183
    /// May block if another thread is currently attempting to initialize the cell. The cell is
    /// guaranteed to contain a value when set returns, though not necessarily the one provided.
    ///
    /// Returns `Ok(())` if the cell's value was set by this call.
A
Aleksey Kladov 已提交
184
    ///
A
Ashley Mannix 已提交
185 186
    /// # Examples
    ///
A
Aleksey Kladov 已提交
187
    /// ```
A
Ashley Mannix 已提交
188 189
    /// #![feature(once_cell)]
    ///
A
Aleksey Kladov 已提交
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
    /// use std::lazy::SyncOnceCell;
    ///
    /// static CELL: SyncOnceCell<i32> = SyncOnceCell::new();
    ///
    /// fn main() {
    ///     assert!(CELL.get().is_none());
    ///
    ///     std::thread::spawn(|| {
    ///         assert_eq!(CELL.set(92), Ok(()));
    ///     }).join().unwrap();
    ///
    ///     assert_eq!(CELL.set(62), Err(62));
    ///     assert_eq!(CELL.get(), Some(&92));
    /// }
    /// ```
A
Ashley Mannix 已提交
205
    #[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    pub fn set(&self, value: T) -> Result<(), T> {
        let mut value = Some(value);
        self.get_or_init(|| value.take().unwrap());
        match value {
            None => Ok(()),
            Some(value) => Err(value),
        }
    }

    /// Gets the contents of the cell, initializing it with `f` if the cell
    /// was empty.
    ///
    /// Many threads may call `get_or_init` concurrently with different
    /// initializing functions, but it is guaranteed that only one function
    /// will be executed.
    ///
    /// # Panics
    ///
    /// If `f` panics, the panic is propagated to the caller, and the cell
    /// remains uninitialized.
    ///
    /// It is an error to reentrantly initialize the cell from `f`. The
    /// exact outcome is unspecified. Current implementation deadlocks, but
    /// this may be changed to a panic in the future.
    ///
A
Ashley Mannix 已提交
231 232
    /// # Examples
    ///
A
Aleksey Kladov 已提交
233
    /// ```
A
Ashley Mannix 已提交
234 235
    /// #![feature(once_cell)]
    ///
A
Aleksey Kladov 已提交
236 237 238 239 240 241 242 243
    /// use std::lazy::SyncOnceCell;
    ///
    /// let cell = SyncOnceCell::new();
    /// let value = cell.get_or_init(|| 92);
    /// assert_eq!(value, &92);
    /// let value = cell.get_or_init(|| unreachable!());
    /// assert_eq!(value, &92);
    /// ```
A
Ashley Mannix 已提交
244
    #[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
    pub fn get_or_init<F>(&self, f: F) -> &T
    where
        F: FnOnce() -> T,
    {
        match self.get_or_try_init(|| Ok::<T, !>(f())) {
            Ok(val) => val,
        }
    }

    /// Gets the contents of the cell, initializing it with `f` if
    /// the cell was empty. If the cell was empty and `f` failed, an
    /// error is returned.
    ///
    /// # Panics
    ///
    /// If `f` panics, the panic is propagated to the caller, and
    /// the cell remains uninitialized.
    ///
    /// It is an error to reentrantly initialize the cell from `f`.
    /// The exact outcome is unspecified. Current implementation
    /// deadlocks, but this may be changed to a panic in the future.
    ///
A
Ashley Mannix 已提交
267 268
    /// # Examples
    ///
A
Aleksey Kladov 已提交
269
    /// ```
A
Ashley Mannix 已提交
270 271
    /// #![feature(once_cell)]
    ///
A
Aleksey Kladov 已提交
272 273 274 275 276 277 278 279 280 281 282
    /// use std::lazy::SyncOnceCell;
    ///
    /// let cell = SyncOnceCell::new();
    /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
    /// assert!(cell.get().is_none());
    /// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
    ///     Ok(92)
    /// });
    /// assert_eq!(value, Ok(&92));
    /// assert_eq!(cell.get(), Some(&92))
    /// ```
A
Ashley Mannix 已提交
283
    #[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
284 285 286 287 288
    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
    where
        F: FnOnce() -> Result<T, E>,
    {
        // Fast path check
A
Ashley Mannix 已提交
289 290 291 292
        // NOTE: We need to perform an acquire on the state in this method
        // in order to correctly synchronize `SyncLazy::force`. This is
        // currently done by calling `self.get()`, which in turn calls
        // `self.is_initialized()`, which in turn performs the acquire.
A
Aleksey Kladov 已提交
293 294 295 296 297 298
        if let Some(value) = self.get() {
            return Ok(value);
        }
        self.initialize(f)?;

        debug_assert!(self.is_initialized());
A
Ashley Mannix 已提交
299

F
Flying-Toast 已提交
300
        // SAFETY: The inner value has been initialized
A
Aleksey Kladov 已提交
301 302 303
        Ok(unsafe { self.get_unchecked() })
    }

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    /// Internal-only API that gets the contents of the cell, initializing it
    /// in two steps with `f` and `g` if the cell was empty.
    ///
    /// `f` is called to construct the value, which is then moved into the cell
    /// and given as a (pinned) mutable reference to `g` to finish
    /// initialization.
    ///
    /// This allows `g` to inspect an manipulate the value after it has been
    /// moved into its final place in the cell, but before the cell is
    /// considered initialized.
    ///
    /// # Panics
    ///
    /// If `f` or `g` panics, the panic is propagated to the caller, and the
    /// cell remains uninitialized.
    ///
    /// With the current implementation, if `g` panics, the value from `f` will
    /// not be dropped. This should probably be fixed if this is ever used for
    /// a type where this matters.
    ///
    /// It is an error to reentrantly initialize the cell from `f`. The exact
    /// outcome is unspecified. Current implementation deadlocks, but this may
    /// be changed to a panic in the future.
    pub(crate) fn get_or_init_pin<F, G>(self: Pin<&Self>, f: F, g: G) -> Pin<&T>
    where
        F: FnOnce() -> T,
        G: FnOnce(Pin<&mut T>),
    {
        if let Some(value) = self.get_ref().get() {
            // SAFETY: The inner value was already initialized, and will not be
            // moved anymore.
            return unsafe { Pin::new_unchecked(value) };
        }

        let slot = &self.value;

        // Ignore poisoning from other threads
        // If another thread panics, then we'll be able to run our closure
        self.once.call_once_force(|_| {
            let value = f();
            // SAFETY: We use the Once (self.once) to guarantee unique access
            // to the UnsafeCell (slot).
            let value: &mut T = unsafe { (&mut *slot.get()).write(value) };
            // SAFETY: The value has been written to its final place in
            // self.value. We do not to move it anymore, which we promise here
            // with a Pin<&mut T>.
            g(unsafe { Pin::new_unchecked(value) });
        });

        // SAFETY: The inner value has been initialized, and will not be moved
        // anymore.
        unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) }
    }

A
Aleksey Kladov 已提交
358 359 360 361 362 363
    /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns
    /// `None` if the cell was empty.
    ///
    /// # Examples
    ///
    /// ```
A
Ashley Mannix 已提交
364 365
    /// #![feature(once_cell)]
    ///
A
Aleksey Kladov 已提交
366 367 368 369 370 371 372 373 374
    /// use std::lazy::SyncOnceCell;
    ///
    /// let cell: SyncOnceCell<String> = SyncOnceCell::new();
    /// assert_eq!(cell.into_inner(), None);
    ///
    /// let cell = SyncOnceCell::new();
    /// cell.set("hello".to_string()).unwrap();
    /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
    /// ```
A
Ashley Mannix 已提交
375
    #[unstable(feature = "once_cell", issue = "74465")]
A
Ashley Mannix 已提交
376
    pub fn into_inner(mut self) -> Option<T> {
377
        self.take()
A
Ashley Mannix 已提交
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
    }

    /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
    ///
    /// Has no effect and returns `None` if the `SyncOnceCell` hasn't been initialized.
    ///
    /// Safety is guaranteed by requiring a mutable reference.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(once_cell)]
    ///
    /// use std::lazy::SyncOnceCell;
    ///
    /// let mut cell: SyncOnceCell<String> = SyncOnceCell::new();
    /// assert_eq!(cell.take(), None);
    ///
    /// let mut cell = SyncOnceCell::new();
    /// cell.set("hello".to_string()).unwrap();
    /// assert_eq!(cell.take(), Some("hello".to_string()));
    /// assert_eq!(cell.get(), None);
    /// ```
A
Ashley Mannix 已提交
401
    #[unstable(feature = "once_cell", issue = "74465")]
A
Ashley Mannix 已提交
402 403
    pub fn take(&mut self) -> Option<T> {
        if self.is_initialized() {
404 405 406 407 408
            self.once = Once::new();
            // SAFETY: `self.value` is initialized and contains a valid `T`.
            // `self.once` is reset, so `is_initialized()` will be false again
            // which prevents the value from being read twice.
            unsafe { Some((&mut *self.value.get()).assume_init_read()) }
A
Ashley Mannix 已提交
409 410 411
        } else {
            None
        }
A
Aleksey Kladov 已提交
412 413 414 415
    }

    #[inline]
    fn is_initialized(&self) -> bool {
416
        self.once.is_completed()
A
Aleksey Kladov 已提交
417 418 419 420 421 422 423 424 425
    }

    #[cold]
    fn initialize<F, E>(&self, f: F) -> Result<(), E>
    where
        F: FnOnce() -> Result<T, E>,
    {
        let mut res: Result<(), E> = Ok(());
        let slot = &self.value;
426 427 428 429

        // Ignore poisoning from other threads
        // If another thread panics, then we'll be able to run our closure
        self.once.call_once_force(|p| {
A
Aleksey Kladov 已提交
430 431
            match f() {
                Ok(value) => {
A
Ashley Mannix 已提交
432
                    unsafe { (&mut *slot.get()).write(value) };
A
Aleksey Kladov 已提交
433 434 435
                }
                Err(e) => {
                    res = Err(e);
436 437 438 439

                    // Treat the underlying `Once` as poisoned since we
                    // failed to initialize our value. Calls
                    p.poison();
A
Aleksey Kladov 已提交
440 441 442 443 444
                }
            }
        });
        res
    }
A
Ashley Mannix 已提交
445

446 447 448
    /// # Safety
    ///
    /// The value must be initialized
A
Ashley Mannix 已提交
449 450
    unsafe fn get_unchecked(&self) -> &T {
        debug_assert!(self.is_initialized());
451
        (&*self.value.get()).assume_init_ref()
A
Ashley Mannix 已提交
452 453
    }

454 455 456
    /// # Safety
    ///
    /// The value must be initialized
A
Ashley Mannix 已提交
457 458
    unsafe fn get_unchecked_mut(&mut self) -> &mut T {
        debug_assert!(self.is_initialized());
459
        (&mut *self.value.get()).assume_init_mut()
A
Ashley Mannix 已提交
460 461 462
    }
}

463
unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
A
Ashley Mannix 已提交
464
    fn drop(&mut self) {
465
        if self.is_initialized() {
466
            // SAFETY: The cell is initialized and being dropped, so it can't
467 468 469 470
            // be accessed again. We also don't touch the `T` other than
            // dropping it, which validates our usage of #[may_dangle].
            unsafe { (&mut *self.value.get()).assume_init_drop() };
        }
A
Ashley Mannix 已提交
471
    }
A
Aleksey Kladov 已提交
472 473 474 475
}

/// A value which is initialized on the first access.
///
A
Ashley Mannix 已提交
476 477 478
/// This type is a thread-safe `Lazy`, and can be used in statics.
///
/// # Examples
A
Aleksey Kladov 已提交
479 480
///
/// ```
A
Ashley Mannix 已提交
481 482
/// #![feature(once_cell)]
///
A
Aleksey Kladov 已提交
483 484
/// use std::collections::HashMap;
///
A
Ashley Mannix 已提交
485
/// use std::lazy::SyncLazy;
A
Aleksey Kladov 已提交
486
///
A
Ashley Mannix 已提交
487
/// static HASHMAP: SyncLazy<HashMap<i32, String>> = SyncLazy::new(|| {
A
Aleksey Kladov 已提交
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
///     println!("initializing");
///     let mut m = HashMap::new();
///     m.insert(13, "Spica".to_string());
///     m.insert(74, "Hoyten".to_string());
///     m
/// });
///
/// fn main() {
///     println!("ready");
///     std::thread::spawn(|| {
///         println!("{:?}", HASHMAP.get(&13));
///     }).join().unwrap();
///     println!("{:?}", HASHMAP.get(&74));
///
///     // Prints:
///     //   ready
///     //   initializing
///     //   Some("Spica")
///     //   Some("Hoyten")
/// }
/// ```
A
Ashley Mannix 已提交
509
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
510 511 512 513 514
pub struct SyncLazy<T, F = fn() -> T> {
    cell: SyncOnceCell<T>,
    init: Cell<Option<F>>,
}

A
Ashley Mannix 已提交
515
#[unstable(feature = "once_cell", issue = "74465")]
A
Ashley Mannix 已提交
516
impl<T: fmt::Debug, F> fmt::Debug for SyncLazy<T, F> {
A
Aleksey Kladov 已提交
517
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
518
        f.debug_struct("Lazy").field("cell", &self.cell).finish_non_exhaustive()
A
Aleksey Kladov 已提交
519 520 521 522 523 524 525 526
    }
}

// We never create a `&F` from a `&SyncLazy<T, F>` so it is fine
// to not impl `Sync` for `F`
// we do create a `&mut Option<F>` in `force`, but this is
// properly synchronized, so it only happens once
// so it also does not contribute to this impl.
A
Ashley Mannix 已提交
527
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
528 529 530
unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {}
// auto-derived `Send` impl is OK.

A
Ashley Mannix 已提交
531
#[unstable(feature = "once_cell", issue = "74465")]
532 533 534
impl<T, F: UnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {}
#[unstable(feature = "once_cell", issue = "74465")]
impl<T, F: UnwindSafe> UnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: UnwindSafe {}
A
Aleksey Kladov 已提交
535 536 537 538

impl<T, F> SyncLazy<T, F> {
    /// Creates a new lazy value with the given initializing
    /// function.
A
Ashley Mannix 已提交
539
    #[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
540 541 542 543 544 545 546 547 548 549
    pub const fn new(f: F) -> SyncLazy<T, F> {
        SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) }
    }
}

impl<T, F: FnOnce() -> T> SyncLazy<T, F> {
    /// Forces the evaluation of this lazy value and
    /// returns a reference to result. This is equivalent
    /// to the `Deref` impl, but is explicit.
    ///
A
Ashley Mannix 已提交
550 551
    /// # Examples
    ///
A
Aleksey Kladov 已提交
552
    /// ```
A
Ashley Mannix 已提交
553 554
    /// #![feature(once_cell)]
    ///
A
Aleksey Kladov 已提交
555 556 557 558 559 560 561
    /// use std::lazy::SyncLazy;
    ///
    /// let lazy = SyncLazy::new(|| 92);
    ///
    /// assert_eq!(SyncLazy::force(&lazy), &92);
    /// assert_eq!(&*lazy, &92);
    /// ```
A
Ashley Mannix 已提交
562
    #[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
563 564 565
    pub fn force(this: &SyncLazy<T, F>) -> &T {
        this.cell.get_or_init(|| match this.init.take() {
            Some(f) => f(),
A
Ashley Mannix 已提交
566
            None => panic!("Lazy instance has previously been poisoned"),
A
Aleksey Kladov 已提交
567 568 569 570
        })
    }
}

A
Ashley Mannix 已提交
571
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
572 573 574 575 576 577 578
impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> {
    type Target = T;
    fn deref(&self) -> &T {
        SyncLazy::force(self)
    }
}

A
Ashley Mannix 已提交
579
#[unstable(feature = "once_cell", issue = "74465")]
A
Aleksey Kladov 已提交
580 581 582 583 584 585
impl<T: Default> Default for SyncLazy<T> {
    /// Creates a new lazy value using `Default` as the initializing function.
    fn default() -> SyncLazy<T> {
        SyncLazy::new(T::default)
    }
}