use alloc::boxed::Box;
use core::sync::atomic::{AtomicBool, Ordering};
use once_cell::race::OnceBox;
pub(crate) struct OnceTable<T> {
claimed: AtomicBool,
cell: OnceBox<T>,
}
impl<T> OnceTable<T> {
pub(crate) const fn new() -> Self {
OnceTable {
claimed: AtomicBool::new(false),
cell: OnceBox::new(),
}
}
pub(crate) fn get_or_init(&self, f: impl FnOnce() -> T) -> &T {
if let Some(value) = self.cell.get() {
return value;
}
if !self.claimed.swap(true, Ordering::AcqRel) {
let _ = self.cell.set(Box::new(f()));
}
loop {
if let Some(value) = self.cell.get() {
return value;
}
core::hint::spin_loop();
}
}
}