use crate::cell::UnsafeCell;
use crate::fmt;
use crate::marker::PhantomData;
use crate::mem::MaybeUninit;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::sync::Once;
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
pub struct OnceLock<T> {
once: Once,
value: UnsafeCell<MaybeUninit<T>>,
_marker: PhantomData<T>,
}
impl<T> OnceLock<T> {
#[inline]
#[must_use]
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
pub const fn new() -> OnceLock<T> {
OnceLock {
once: Once::new(),
value: UnsafeCell::new(MaybeUninit::uninit()),
_marker: PhantomData,
}
}
#[inline]
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
pub fn get(&self) -> Option<&T> {
if self.is_initialized() {
Some(unsafe { self.get_unchecked() })
} else {
None
}
}
#[inline]
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.is_initialized() {
Some(unsafe { self.get_unchecked_mut() })
} else {
None
}
}
#[inline]
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
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),
}
}
#[inline]
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
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,
}
}
#[inline]
#[unstable(feature = "once_cell_try", issue = "109737")]
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
where
F: FnOnce() -> Result<T, E>,
{
if let Some(value) = self.get() {
return Ok(value);
}
self.initialize(f)?;
debug_assert!(self.is_initialized());
Ok(unsafe { self.get_unchecked() })
}
#[inline]
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
pub fn into_inner(mut self) -> Option<T> {
self.take()
}
#[inline]
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
pub fn take(&mut self) -> Option<T> {
if self.is_initialized() {
self.once = Once::new();
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;
self.once.call_once_force(|p| {
match f() {
Ok(value) => {
unsafe { (&mut *slot.get()).write(value) };
}
Err(e) => {
res = Err(e);
p.poison();
}
}
});
res
}
#[inline]
unsafe fn get_unchecked(&self) -> &T {
debug_assert!(self.is_initialized());
(&*self.value.get()).assume_init_ref()
}
#[inline]
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
debug_assert!(self.is_initialized());
(&mut *self.value.get()).assume_init_mut()
}
}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
unsafe impl<T: Send> Send for OnceLock<T> {}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
impl<T> const Default for OnceLock<T> {
#[inline]
fn default() -> OnceLock<T> {
OnceLock::new()
}
}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
impl<T: fmt::Debug> fmt::Debug for OnceLock<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)"),
}
}
}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
impl<T: Clone> Clone for OnceLock<T> {
#[inline]
fn clone(&self) -> OnceLock<T> {
let cell = Self::new();
if let Some(value) = self.get() {
match cell.set(value.clone()) {
Ok(()) => (),
Err(_) => unreachable!(),
}
}
cell
}
}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
impl<T> From<T> for OnceLock<T> {
#[inline]
fn from(value: T) -> Self {
let cell = Self::new();
match cell.set(value) {
Ok(()) => cell,
Err(_) => unreachable!(),
}
}
}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
impl<T: PartialEq> PartialEq for OnceLock<T> {
#[inline]
fn eq(&self, other: &OnceLock<T>) -> bool {
self.get() == other.get()
}
}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
impl<T: Eq> Eq for OnceLock<T> {}
#[stable(feature = "once_cell", since = "CURRENT_RUSTC_VERSION")]
unsafe impl<#[may_dangle] T> Drop for OnceLock<T> {
#[inline]
fn drop(&mut self) {
if self.is_initialized() {
unsafe { (&mut *self.value.get()).assume_init_drop() };
}
}
}
#[cfg(test)]
mod tests;