use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
pub struct Once<T> {
set: crate::sync::atomic::AtomicBool,
cell: UnsafeCell<MaybeUninit<T>>,
}
unsafe impl<T: Sync> Sync for Once<T> {}
impl<T> Once<T> {
#[cfg(not(loom))]
pub const fn new() -> Self {
Self::new_impl()
}
#[cfg(loom)]
pub fn new() -> Self {
Self::new_impl()
}
#[cfg(not(loom))]
const fn new_impl() -> Self {
Self {
set: crate::sync::atomic::AtomicBool::new(false),
cell: UnsafeCell::new(MaybeUninit::uninit()),
}
}
#[cfg(loom)]
fn new_impl() -> Self {
Self {
set: crate::sync::atomic::AtomicBool::new(false),
cell: UnsafeCell::new(MaybeUninit::uninit()),
}
}
pub fn set(&self, value: T) -> Result<(), T> {
if self.set.load(crate::sync::atomic::Ordering::Acquire) {
return Err(value);
}
unsafe {
(*self.cell.get()).write(value);
}
self.set.store(true, crate::sync::atomic::Ordering::Release);
Ok(())
}
pub fn get(&self) -> Option<&T> {
if !self.set.load(crate::sync::atomic::Ordering::Acquire) {
return None;
}
unsafe { Some(&*(*self.cell.get()).as_ptr()) }
}
}
impl<T> Default for Once<T> {
fn default() -> Self {
Self::new()
}
}