pub use implementation::{Once, OnceLock, OnceState};
#[cfg(feature = "std")]
use std::sync as implementation;
#[cfg(not(feature = "std"))]
mod implementation {
use core::{
fmt,
panic::{RefUnwindSafe, UnwindSafe},
};
pub struct OnceLock<T> {
inner: spin::Once<T>,
}
impl<T> OnceLock<T> {
#[must_use]
pub const fn new() -> Self {
Self {
inner: spin::Once::new(),
}
}
pub fn get(&self) -> Option<&T> {
self.inner.get()
}
pub fn get_mut(&mut self) -> Option<&mut T> {
self.inner.get_mut()
}
pub fn set(&self, value: T) -> Result<(), T> {
let mut value = Some(value);
self.inner.call_once(|| value.take().unwrap());
match value {
Some(value) => Err(value),
None => Ok(()),
}
}
pub fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
{
self.inner.call_once(f)
}
pub fn into_inner(mut self) -> Option<T> {
self.take()
}
pub fn take(&mut self) -> Option<T> {
if self.inner.is_completed() {
let mut inner = spin::Once::new();
core::mem::swap(&mut self.inner, &mut inner);
inner.try_into_inner()
} else {
None
}
}
}
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
impl<T> Default for OnceLock<T> {
fn default() -> OnceLock<T> {
OnceLock::new()
}
}
impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_tuple("OnceLock");
match self.get() {
Some(v) => d.field(v),
None => d.field(&format_args!("<uninit>")),
};
d.finish()
}
}
impl<T: Clone> Clone for OnceLock<T> {
fn clone(&self) -> OnceLock<T> {
let cell = Self::new();
if let Some(value) = self.get() {
cell.set(value.clone()).ok().unwrap();
}
cell
}
}
impl<T> From<T> for OnceLock<T> {
fn from(value: T) -> Self {
let cell = Self::new();
cell.set(value).map(move |_| cell).ok().unwrap()
}
}
impl<T: PartialEq> PartialEq for OnceLock<T> {
fn eq(&self, other: &OnceLock<T>) -> bool {
self.get() == other.get()
}
}
impl<T: Eq> Eq for OnceLock<T> {}
pub struct Once {
inner: OnceLock<()>,
}
impl Once {
#[expect(clippy::new_without_default, reason = "matching std::sync::Once")]
pub const fn new() -> Self {
Self {
inner: OnceLock::new(),
}
}
pub fn call_once<F: FnOnce()>(&self, f: F) {
self.inner.get_or_init(f);
}
pub fn call_once_force<F: FnOnce(&OnceState)>(&self, f: F) {
const STATE: OnceState = OnceState { _private: () };
self.call_once(move || f(&STATE));
}
pub fn is_completed(&self) -> bool {
self.inner.get().is_some()
}
}
impl RefUnwindSafe for Once {}
impl UnwindSafe for Once {}
impl fmt::Debug for Once {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Once").finish_non_exhaustive()
}
}
pub struct OnceState {
_private: (),
}
impl OnceState {
pub fn is_poisoned(&self) -> bool {
false
}
}
impl fmt::Debug for OnceState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OnceState")
.field("poisoned", &self.is_poisoned())
.finish()
}
}
}