use std::cell::UnsafeCell;
pub(crate) struct OnceCell<T> {
inner: UnsafeCell<Option<T>>,
}
impl<T> Default for OnceCell<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> OnceCell<T> {
pub(crate) const fn new() -> OnceCell<T> {
OnceCell {
inner: UnsafeCell::new(None),
}
}
pub(crate) fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
{
if let Some(val) = self.get() {
return val;
}
let val = f();
assert!(self.set(val).is_ok(), "reentrant init");
self.get().expect("We set the value in the line above")
}
pub(crate) fn get(&self) -> Option<&T> {
unsafe { &*self.inner.get() }.as_ref()
}
pub(crate) fn set(&self, value: T) -> Result<(), T> {
let slot = unsafe { &*self.inner.get() };
if slot.is_some() {
return Err(value);
}
let slot = unsafe { &mut *self.inner.get() };
*slot = Some(value);
Ok(())
}
}