blob: 3598598cfa02a6bc033c1e03b2d64231d61651da [file] [log] [blame]
use crate::cell::UnsafeCell;
use crate::mem::ManuallyDrop;
use crate::ops::Deref;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::sync::Once;
use crate::{fmt, ptr};
use super::once::ExclusiveState;
// We use the state of a Once as discriminant value. Upon creation, the state is
// "incomplete" and `f` contains the initialization closure. In the first call to
// `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state
// is changed to "complete". If it panics, the Once is poisoned, so none of the
// two fields is initialized.
union Data<T, F> {
value: ManuallyDrop<T>,
f: ManuallyDrop<F>,
}
/// A value which is initialized on the first access.
///
/// This type is a thread-safe [`LazyCell`], and can be used in statics.
///
/// [`LazyCell`]: crate::cell::LazyCell
///
/// # Examples
///
/// Initialize static variables with `LazyLock`.
///
/// ```
/// #![feature(lazy_cell)]
///
/// use std::collections::HashMap;
///
/// use std::sync::LazyLock;
///
/// static HASHMAP: LazyLock<HashMap<i32, String>> = LazyLock::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")
/// }
/// ```
/// Initialize fields with `LazyLock`.
/// ```
/// #![feature(lazy_cell)]
///
/// use std::sync::LazyLock;
///
/// #[derive(Debug)]
/// struct UseCellLock {
/// number: LazyLock<u32>,
/// }
/// fn main() {
/// let lock: LazyLock<u32> = LazyLock::new(|| 0u32);
///
/// let data = UseCellLock { number: lock };
/// println!("{}", *data.number);
/// }
/// ```
#[unstable(feature = "lazy_cell", issue = "109736")]
pub struct LazyLock<T, F = fn() -> T> {
once: Once,
data: UnsafeCell<Data<T, F>>,
}
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
/// Creates a new lazy value with the given initializing
/// function.
#[inline]
#[unstable(feature = "lazy_cell", issue = "109736")]
pub const fn new(f: F) -> LazyLock<T, F> {
LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
}
/// Creates a new lazy value that is already initialized.
#[inline]
#[cfg(test)]
pub(crate) fn preinit(value: T) -> LazyLock<T, F> {
let once = Once::new();
once.call_once(|| {});
LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) }
}
/// Consumes this `LazyLock` returning the stored value.
///
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
///
/// # Examples
///
/// ```
/// #![feature(lazy_cell)]
/// #![feature(lazy_cell_consume)]
///
/// use std::sync::LazyLock;
///
/// let hello = "Hello, World!".to_string();
///
/// let lazy = LazyLock::new(|| hello.to_uppercase());
///
/// assert_eq!(&*lazy, "HELLO, WORLD!");
/// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
/// ```
#[unstable(feature = "lazy_cell_consume", issue = "109736")]
pub fn into_inner(mut this: Self) -> Result<T, F> {
let state = this.once.state();
match state {
ExclusiveState::Poisoned => panic!("LazyLock instance has previously been poisoned"),
state => {
let this = ManuallyDrop::new(this);
let data = unsafe { ptr::read(&this.data) }.into_inner();
match state {
ExclusiveState::Incomplete => Err(ManuallyDrop::into_inner(unsafe { data.f })),
ExclusiveState::Complete => Ok(ManuallyDrop::into_inner(unsafe { data.value })),
ExclusiveState::Poisoned => unreachable!(),
}
}
}
}
/// 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(lazy_cell)]
///
/// use std::sync::LazyLock;
///
/// let lazy = LazyLock::new(|| 92);
///
/// assert_eq!(LazyLock::force(&lazy), &92);
/// assert_eq!(&*lazy, &92);
/// ```
#[inline]
#[unstable(feature = "lazy_cell", issue = "109736")]
pub fn force(this: &LazyLock<T, F>) -> &T {
this.once.call_once(|| {
// SAFETY: `call_once` only runs this closure once, ever.
let data = unsafe { &mut *this.data.get() };
let f = unsafe { ManuallyDrop::take(&mut data.f) };
let value = f();
data.value = ManuallyDrop::new(value);
});
// SAFETY:
// There are four possible scenarios:
// * the closure was called and initialized `value`.
// * the closure was called and panicked, so this point is never reached.
// * the closure was not called, but a previous call initialized `value`.
// * the closure was not called because the Once is poisoned, so this point
// is never reached.
// So `value` has definitely been initialized and will not be modified again.
unsafe { &*(*this.data.get()).value }
}
}
impl<T, F> LazyLock<T, F> {
/// Get the inner value if it has already been initialized.
fn get(&self) -> Option<&T> {
if self.once.is_completed() {
// SAFETY:
// The closure has been run successfully, so `value` has been initialized
// and will not be modified again.
Some(unsafe { &*(*self.data.get()).value })
} else {
None
}
}
}
#[unstable(feature = "lazy_cell", issue = "109736")]
impl<T, F> Drop for LazyLock<T, F> {
fn drop(&mut self) {
match self.once.state() {
ExclusiveState::Incomplete => unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) },
ExclusiveState::Complete => unsafe {
ManuallyDrop::drop(&mut self.data.get_mut().value)
},
ExclusiveState::Poisoned => {}
}
}
}
#[unstable(feature = "lazy_cell", issue = "109736")]
impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
LazyLock::force(self)
}
}
#[unstable(feature = "lazy_cell", issue = "109736")]
impl<T: Default> Default for LazyLock<T> {
/// Creates a new lazy value using `Default` as the initializing function.
#[inline]
fn default() -> LazyLock<T> {
LazyLock::new(T::default)
}
}
#[unstable(feature = "lazy_cell", issue = "109736")]
impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_tuple("LazyLock");
match self.get() {
Some(v) => d.field(v),
None => d.field(&format_args!("<uninit>")),
};
d.finish()
}
}
// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
// to not impl `Sync` for `F`
#[unstable(feature = "lazy_cell", issue = "109736")]
unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {}
// auto-derived `Send` impl is OK.
#[unstable(feature = "lazy_cell", issue = "109736")]
impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> {}
#[unstable(feature = "lazy_cell", issue = "109736")]
impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F> {}
#[cfg(test)]
mod tests;