use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
use crate::Mutex;
pub struct OnceLock<T> {
elem: UnsafeCell<MaybeUninit<T>>,
is_init: Mutex<bool>,
}
impl<T> OnceLock<T> {
pub const fn new() -> Self {
Self {
elem: UnsafeCell::new(MaybeUninit::uninit()),
is_init: Mutex::new(false),
}
}
pub fn get_or_init<F>(&self, init: F) -> &T
where
F: FnOnce() -> T
{
{
let mut lock = self.is_init.lock();
if !*lock {
unsafe {
self.elem.get().as_mut().unwrap().write(init());
}
*lock = true;
}
}
unsafe { self.elem.get().as_ref().unwrap().assume_init_ref() }
}
pub fn get(&self) -> Option<&T> {
let lock = self.is_init.lock();
lock.then(|| {
unsafe { self.elem.get().as_ref().unwrap().assume_init_ref() }
})
}
}
impl<T> Default for OnceLock<T> {
fn default() -> Self {
Self::new()
}
}
unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
unsafe impl<T: Send> Send for OnceLock<T> {}