use crate::polyfill::{FinishNonExhaustive, UntaggedOptionCell};
use core::cell::UnsafeCell;
use core::fmt::{Debug, Formatter};
use core::mem::ManuallyDrop;
use core::ops::Deref;
#[cfg(sync_backend = "parking_lot")]
mod parking_lot;
#[cfg(sync_backend = "parking_lot")]
use self::parking_lot as backend;
#[cfg(sync_backend = "std")]
mod std_sync;
#[cfg(sync_backend = "std")]
use self::std_sync as backend;
#[cfg(sync_backend = "spin")]
mod spin;
#[cfg(sync_backend = "spin")]
use self::spin as backend;
pub const LEGACY_POISON_BEHAVIOR: bool = backend::LEGACY_POISON_BEHAVIOR;
pub struct OnceLock<T> {
once: backend::Once,
value: UntaggedOptionCell<T>,
}
impl<T> Default for OnceLock<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T> OnceLock<T> {
#[inline]
#[rustversion::attr(since(1.32), const)] pub fn new() -> Self {
OnceLock {
once: backend::Once::new(),
value: UntaggedOptionCell::uninit(),
}
}
#[inline]
pub fn set(&self, value: T) -> Result<(), T> {
let mut value = Some(value);
self.get_or_init(|| value.take().unwrap());
if let Some(failed) = value {
Err(failed)
} else {
Ok(())
}
}
#[inline]
pub unsafe fn get_unchecked(&self) -> &T {
debug_assert!(self.get().is_some(), "UB: access uninitialized data");
unsafe { &*self.value.get_ptr_unchecked() }
}
#[inline]
pub fn get(&self) -> Option<&T> {
if self.once.is_completed() {
Some(unsafe { self.get_unchecked() })
} else {
None
}
}
#[inline]
pub fn get_or_init<F: FnOnce() -> T>(&self, f: F) -> &T {
self.get().unwrap_or_else(|| self.init_fallback(f))
}
#[cold]
fn init_fallback(&self, func: impl FnOnce() -> T) -> &T {
self.once.call_once_force(|| {
let value = func();
unsafe {
self.value.write(value);
}
});
unsafe { &*self.value.get_ptr_unchecked() }
}
#[inline]
pub fn into_inner(self) -> Option<T> {
let mut this = ManuallyDrop::new(self);
this.take()
}
#[inline]
pub fn take(&mut self) -> Option<T> {
if self.get().is_some() {
let guard = AbortGuard;
struct AbortGuard;
impl Drop for AbortGuard {
fn drop(&mut self) {
panic!("Panic here could cause invalid state to be seen");
}
}
let value = unsafe { core::ptr::read(self.value.get_ptr_unchecked()) };
self.once = backend::Once::new();
core::mem::forget(guard);
Some(value)
} else {
None
}
}
}
impl<T> Drop for OnceLock<T> {
fn drop(&mut self) {
drop(self.take());
}
}
impl<T: Clone> Clone for OnceLock<T> {
fn clone(&self) -> Self {
match self.get() {
None => OnceLock::new(),
Some(inner) => OnceLock::from(inner.clone()),
}
}
}
unsafe impl<T: Send> Send for OnceLock<T> {}
unsafe impl<T: Sync> Sync for OnceLock<T> {}
impl<T> From<T> for OnceLock<T> {
fn from(value: T) -> Self {
let res = OnceLock::new();
match res.set(value) {
Ok(()) => res,
Err(_) => {
unsafe { core::hint::unreachable_unchecked() }
}
}
}
}
enum LazyState<T, F> {
Initialized(T),
InProgress,
Uninitialized(F),
}
pub struct LazyLock<T, F = fn() -> T> {
once: backend::Once,
state: UnsafeCell<LazyState<T, F>>,
}
impl<T, F> LazyLock<T, F> {
#[inline]
#[rustversion::attr(since(1.32), const)] pub fn new(func: F) -> Self {
LazyLock {
once: backend::Once::new(),
state: UnsafeCell::new(LazyState::Uninitialized(func)),
}
}
#[inline]
pub fn get(this: &Self) -> Option<&T> {
if this.once.is_completed() {
Some(unsafe { Self::get_unchecked(this) })
} else {
None
}
}
#[inline]
unsafe fn get_unchecked(this: &Self) -> &T {
match unsafe { &*this.state.get() } {
LazyState::Uninitialized(_) | LazyState::InProgress => {
unsafe { core::hint::unreachable_unchecked() }
}
LazyState::Initialized(ref value) => value,
}
}
}
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
#[inline]
#[cfg_attr(has_track_caller, track_caller)]
pub fn force(this: &Self) -> &T {
Self::get(this).unwrap_or_else(|| Self::init_fallback(this))
}
#[cold]
#[cfg_attr(has_track_caller, track_caller)]
fn init_fallback(this: &Self) -> &T {
this.once.call_once(|| {
let this = unsafe { &mut *this.state.get() };
let func = match core::mem::replace(this, LazyState::InProgress) {
LazyState::Initialized(_) | LazyState::InProgress => unreachable!(),
LazyState::Uninitialized(func) => func,
};
*this = LazyState::Initialized(func());
});
unsafe { Self::get_unchecked(this) }
}
}
impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
LazyLock::force(self)
}
}
impl<T: Debug, F> Debug for LazyLock<T, F> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LazyLock")
.field("value", &Self::get(self))
.polyfill_finish_non_exhaustive()
}
}