use crate::Python;
use std::cell::UnsafeCell;
#[allow(clippy::upper_case_acronyms)]
pub struct GILOnceCell<T>(UnsafeCell<Option<T>>);
unsafe impl<T: Send + Sync> Sync for GILOnceCell<T> {}
unsafe impl<T: Send> Send for GILOnceCell<T> {}
impl<T> GILOnceCell<T> {
pub const fn new() -> Self {
Self(UnsafeCell::new(None))
}
pub fn get(&self, _py: Python) -> Option<&T> {
unsafe { &*self.0.get() }.as_ref()
}
pub fn get_or_init<F>(&self, py: Python, f: F) -> &T
where
F: FnOnce() -> T,
{
let inner = unsafe { &*self.0.get() }.as_ref();
if let Some(value) = inner {
return value;
}
let value = f();
let _ = self.set(py, value);
self.get(py).unwrap()
}
pub fn get_mut(&mut self) -> Option<&mut T> {
unsafe { &mut *self.0.get() }.as_mut()
}
pub fn set(&self, _py: Python, value: T) -> Result<(), T> {
let inner = unsafe { &mut *self.0.get() };
if inner.is_some() {
return Err(value);
}
*inner = Some(value);
Ok(())
}
}