use crate::{Event, EventListener, IntoNotification};
use core::cell::{Cell, UnsafeCell};
use core::convert::Infallible;
use core::future::Future;
use core::pin::Pin;
pub struct OnceCell<T> {
active: Event<()>,
passive: Event<()>,
writing: Cell<bool>,
data: UnsafeCell<Option<T>>,
}
impl<T> OnceCell<T> {
pub const fn new() -> OnceCell<T> {
OnceCell {
active: Event::new(),
passive: Event::new(),
writing: Cell::new(false),
data: UnsafeCell::new(None),
}
}
pub fn get_mut(&mut self) -> Option<&mut T> {
unsafe { &mut *self.data.get() }.as_mut()
}
pub fn take(&mut self) -> Option<T> {
unsafe { &mut *self.data.get() }.take()
}
pub fn get(&self) -> Option<&T> {
unsafe { &*self.data.get() }.as_ref()
}
pub async fn set(&self, value: T) -> Result<(), T> {
let mut value = Some(value);
self.get_or_init(async { value.take().unwrap() }).await;
match value {
Some(value) => Err(value),
None => Ok(()),
}
}
pub async fn get_or_try_init<E>(
&self,
setter: impl Future<Output = Result<T, E>>,
) -> Result<&T, E> {
struct UnwriteOnDrop<'a, T> {
cell: &'a OnceCell<T>,
}
impl<T> Drop for UnwriteOnDrop<'_, T> {
fn drop(&mut self) {
self.cell.writing.set(false);
self.cell.active.notify(1);
}
}
let mut listener = EventListener::new(&self.active);
let mut setter = Some(setter);
{
let mut listener = unsafe { Pin::new_unchecked(&mut listener) };
loop {
if let Some(value) = self.get() {
return Ok(value);
}
if self.writing.replace(true) {
listener.as_mut().await;
continue;
}
let guard = UnwriteOnDrop { cell: self };
match setter.take().unwrap().await {
Ok(data) => {
unsafe {
*self.data.get() = Some(data);
}
self.passive.notify(core::usize::MAX.additional());
self.active.notify(core::usize::MAX.additional());
return Ok(self.get().unwrap());
}
Err(e) => {
drop(guard);
return Err(e);
}
}
}
}
}
pub async fn get_or_init(&self, setter: impl Future<Output = T>) -> &T {
match self
.get_or_try_init(async move { Ok::<T, Infallible>(setter.await) })
.await
{
Ok(value) => value,
Err(e) => match e {},
}
}
pub async fn wait(&self) {
let mut listener = EventListener::new(&self.passive);
let mut listener = unsafe { Pin::new_unchecked(&mut listener) };
while self.get().is_none() {
listener.as_mut().await;
}
}
}
impl<T> From<T> for OnceCell<T> {
fn from(value: T) -> OnceCell<T> {
OnceCell {
active: Event::new(),
passive: Event::new(),
writing: Cell::new(false),
data: UnsafeCell::new(Some(value)),
}
}
}