The libs-api team agrees to allow const_trait_impl to appear in the standard library as long as stable code cannot be broken (they are properly gated) this means if the compiler teams thinks it's okay, then it's okay. My priority on constifying would be: 1. Non-generic impls (e.g. Default) or generic impls with no bounds 2. Generic functions with bounds (that use const impls) 3. Generic impls with bounds 4. Impls for traits with associated types For people opening constification PRs: please cc me and/or oli-obk.
617 lines
19 KiB
Rust
617 lines
19 KiB
Rust
//! Lazy values and one-time initialization of static data.
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|
|
|
|
use crate::{
|
|
cell::{Cell, UnsafeCell},
|
|
fmt,
|
|
marker::PhantomData,
|
|
mem::MaybeUninit,
|
|
ops::{Deref, Drop},
|
|
panic::{RefUnwindSafe, UnwindSafe},
|
|
pin::Pin,
|
|
sync::Once,
|
|
};
|
|
|
|
#[doc(inline)]
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
pub use core::lazy::*;
|
|
|
|
/// A synchronization primitive which can be written to only once.
|
|
///
|
|
/// This type is a thread-safe `OnceCell`.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(once_cell)]
|
|
///
|
|
/// use std::lazy::SyncOnceCell;
|
|
///
|
|
/// static CELL: SyncOnceCell<String> = SyncOnceCell::new();
|
|
/// 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!");
|
|
/// ```
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
pub struct SyncOnceCell<T> {
|
|
once: Once,
|
|
// Whether or not the value is initialized is tracked by `state_and_queue`.
|
|
value: UnsafeCell<MaybeUninit<T>>,
|
|
/// `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));
|
|
/// }
|
|
/// ```
|
|
_marker: PhantomData<T>,
|
|
}
|
|
|
|
// Why do we need `T: Send`?
|
|
// Thread A creates a `SyncOnceCell` and shares it with
|
|
// scoped thread B, which fills the cell, which is
|
|
// then destroyed by A. That is, destructor observes
|
|
// a sent value.
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {}
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
unsafe impl<T: Send> Send for SyncOnceCell<T> {}
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {}
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {}
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
|
|
impl<T> const Default for SyncOnceCell<T> {
|
|
/// Creates a new empty cell.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// #![feature(once_cell)]
|
|
///
|
|
/// use std::lazy::SyncOnceCell;
|
|
///
|
|
/// fn main() {
|
|
/// assert_eq!(SyncOnceCell::<()>::new(), SyncOnceCell::default());
|
|
/// }
|
|
/// ```
|
|
fn default() -> SyncOnceCell<T> {
|
|
SyncOnceCell::new()
|
|
}
|
|
}
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self.get() {
|
|
Some(v) => f.debug_tuple("Once").field(v).finish(),
|
|
None => f.write_str("Once(Uninit)"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
impl<T: Clone> Clone for SyncOnceCell<T> {
|
|
fn clone(&self) -> SyncOnceCell<T> {
|
|
let cell = Self::new();
|
|
if let Some(value) = self.get() {
|
|
match cell.set(value.clone()) {
|
|
Ok(()) => (),
|
|
Err(_) => unreachable!(),
|
|
}
|
|
}
|
|
cell
|
|
}
|
|
}
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
impl<T> From<T> for SyncOnceCell<T> {
|
|
/// Create a new cell with its contents set to `value`.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// #![feature(once_cell)]
|
|
///
|
|
/// use std::lazy::SyncOnceCell;
|
|
///
|
|
/// # fn main() -> Result<(), i32> {
|
|
/// let a = SyncOnceCell::from(3);
|
|
/// let b = SyncOnceCell::new();
|
|
/// b.set(3)?;
|
|
/// assert_eq!(a, b);
|
|
/// Ok(())
|
|
/// # }
|
|
/// ```
|
|
fn from(value: T) -> Self {
|
|
let cell = Self::new();
|
|
match cell.set(value) {
|
|
Ok(()) => cell,
|
|
Err(_) => unreachable!(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
impl<T: PartialEq> PartialEq for SyncOnceCell<T> {
|
|
fn eq(&self, other: &SyncOnceCell<T>) -> bool {
|
|
self.get() == other.get()
|
|
}
|
|
}
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
impl<T: Eq> Eq for SyncOnceCell<T> {}
|
|
|
|
impl<T> SyncOnceCell<T> {
|
|
/// Creates a new empty cell.
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
pub const fn new() -> SyncOnceCell<T> {
|
|
SyncOnceCell {
|
|
once: Once::new(),
|
|
value: UnsafeCell::new(MaybeUninit::uninit()),
|
|
_marker: PhantomData,
|
|
}
|
|
}
|
|
|
|
/// Gets the reference to the underlying value.
|
|
///
|
|
/// Returns `None` if the cell is empty, or being initialized. This
|
|
/// method never blocks.
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
pub fn get(&self) -> Option<&T> {
|
|
if self.is_initialized() {
|
|
// Safe b/c checked is_initialized
|
|
Some(unsafe { self.get_unchecked() })
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Gets the mutable reference to the underlying value.
|
|
///
|
|
/// Returns `None` if the cell is empty. This method never blocks.
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
pub fn get_mut(&mut self) -> Option<&mut T> {
|
|
if self.is_initialized() {
|
|
// Safe b/c checked is_initialized and we have a unique access
|
|
Some(unsafe { self.get_unchecked_mut() })
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Sets the contents of this cell to `value`.
|
|
///
|
|
/// 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.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(once_cell)]
|
|
///
|
|
/// 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));
|
|
/// }
|
|
/// ```
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
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.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(once_cell)]
|
|
///
|
|
/// 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);
|
|
/// ```
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
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.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(once_cell)]
|
|
///
|
|
/// 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))
|
|
/// ```
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
|
|
where
|
|
F: FnOnce() -> Result<T, E>,
|
|
{
|
|
// Fast path check
|
|
// 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.
|
|
if let Some(value) = self.get() {
|
|
return Ok(value);
|
|
}
|
|
self.initialize(f)?;
|
|
|
|
debug_assert!(self.is_initialized());
|
|
|
|
// SAFETY: The inner value has been initialized
|
|
Ok(unsafe { self.get_unchecked() })
|
|
}
|
|
|
|
/// 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()) }
|
|
}
|
|
|
|
/// Consumes the `SyncOnceCell`, returning the wrapped value. Returns
|
|
/// `None` if the cell was empty.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(once_cell)]
|
|
///
|
|
/// 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()));
|
|
/// ```
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
pub fn into_inner(mut self) -> Option<T> {
|
|
self.take()
|
|
}
|
|
|
|
/// 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);
|
|
/// ```
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
pub fn take(&mut self) -> Option<T> {
|
|
if self.is_initialized() {
|
|
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()) }
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn is_initialized(&self) -> bool {
|
|
self.once.is_completed()
|
|
}
|
|
|
|
#[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;
|
|
|
|
// Ignore poisoning from other threads
|
|
// If another thread panics, then we'll be able to run our closure
|
|
self.once.call_once_force(|p| {
|
|
match f() {
|
|
Ok(value) => {
|
|
unsafe { (&mut *slot.get()).write(value) };
|
|
}
|
|
Err(e) => {
|
|
res = Err(e);
|
|
|
|
// Treat the underlying `Once` as poisoned since we
|
|
// failed to initialize our value. Calls
|
|
p.poison();
|
|
}
|
|
}
|
|
});
|
|
res
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// The value must be initialized
|
|
unsafe fn get_unchecked(&self) -> &T {
|
|
debug_assert!(self.is_initialized());
|
|
(&*self.value.get()).assume_init_ref()
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// The value must be initialized
|
|
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
|
|
debug_assert!(self.is_initialized());
|
|
(&mut *self.value.get()).assume_init_mut()
|
|
}
|
|
}
|
|
|
|
unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
|
|
fn drop(&mut self) {
|
|
if self.is_initialized() {
|
|
// SAFETY: The cell is initialized and being dropped, so it can't
|
|
// 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 value which is initialized on the first access.
|
|
///
|
|
/// This type is a thread-safe `Lazy`, and can be used in statics.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(once_cell)]
|
|
///
|
|
/// use std::collections::HashMap;
|
|
///
|
|
/// use std::lazy::SyncLazy;
|
|
///
|
|
/// static HASHMAP: SyncLazy<HashMap<i32, String>> = SyncLazy::new(|| {
|
|
/// 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")
|
|
/// }
|
|
/// ```
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
pub struct SyncLazy<T, F = fn() -> T> {
|
|
cell: SyncOnceCell<T>,
|
|
init: Cell<Option<F>>,
|
|
}
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
impl<T: fmt::Debug, F> fmt::Debug for SyncLazy<T, F> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("Lazy").field("cell", &self.cell).finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
// 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.
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {}
|
|
// auto-derived `Send` impl is OK.
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
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 {}
|
|
|
|
impl<T, F> SyncLazy<T, F> {
|
|
/// Creates a new lazy value with the given initializing
|
|
/// function.
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
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.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(once_cell)]
|
|
///
|
|
/// use std::lazy::SyncLazy;
|
|
///
|
|
/// let lazy = SyncLazy::new(|| 92);
|
|
///
|
|
/// assert_eq!(SyncLazy::force(&lazy), &92);
|
|
/// assert_eq!(&*lazy, &92);
|
|
/// ```
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
pub fn force(this: &SyncLazy<T, F>) -> &T {
|
|
this.cell.get_or_init(|| match this.init.take() {
|
|
Some(f) => f(),
|
|
None => panic!("Lazy instance has previously been poisoned"),
|
|
})
|
|
}
|
|
}
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> {
|
|
type Target = T;
|
|
fn deref(&self) -> &T {
|
|
SyncLazy::force(self)
|
|
}
|
|
}
|
|
|
|
#[unstable(feature = "once_cell", issue = "74465")]
|
|
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)
|
|
}
|
|
}
|