use std::{
convert::Infallible,
fmt,
future::{Future, poll_fn},
pin::{Pin, pin},
sync::OnceLock,
task::Poll,
};
use super::{Mutex, MutexGuard};
use crate::Event;
pub struct OnceCell<T> {
value: OnceLock<T>,
initializing: Mutex<()>,
ready: Event,
}
impl<T> OnceCell<T> {
pub const fn new() -> Self {
Self {
value: OnceLock::new(),
initializing: Mutex::new(()),
ready: Event::new(),
}
}
pub fn get(&self) -> Option<&T> {
self.value.get()
}
pub fn get_mut(&mut self) -> Option<&mut T> {
self.value.get_mut()
}
pub fn take(&mut self) -> Option<T> {
self.value.take()
}
pub fn into_inner(self) -> Option<T> {
self.value.into_inner()
}
pub async fn wait(&self) -> &T {
if let Some(value) = self.value.get() {
return value;
}
loop {
let listener = self.ready.listen();
if let Some(value) = self.value.get() {
return value;
}
listener.await;
}
}
pub async fn get_or_init<F, Fut>(&self, init: F) -> &T
where
F: FnOnce() -> Fut,
Fut: Future<Output = T>,
{
let Ok(value) = self
.get_or_try_init(|| async move { Ok::<T, Infallible>(init().await) })
.await;
value
}
pub async fn get_or_try_init<F, Fut, E>(&self, init: F) -> Result<&T, E>
where
F: FnOnce() -> Fut,
Fut: Future<Output = Result<T, E>>,
{
if let Some(value) = self.value.get() {
return Ok(value);
}
let _initializing = match self.lock_or_value().await {
Ok(guard) => guard,
Err(value) => return Ok(value),
};
if let Some(value) = self.value.get() {
return Ok(value);
}
let value = init().await?;
Ok(self.store(value))
}
pub async fn set(&self, value: T) -> Result<&T, T> {
if self.value.get().is_some() {
return Err(value);
}
let Ok(_initializing) = self.lock_or_value().await else {
return Err(value);
};
if self.value.get().is_some() {
return Err(value);
}
Ok(self.store(value))
}
async fn lock_or_value(&self) -> Result<MutexGuard<'_, ()>, &T> {
let mut lock = pin!(self.initializing.lock());
loop {
let mut set = self.ready.listen();
if let Some(value) = self.value.get() {
return Err(value);
}
let guard = poll_fn(|cx| {
if let Poll::Ready(guard) = lock.as_mut().poll(cx) {
return Poll::Ready(Some(guard));
}
Pin::new(&mut set).poll(cx).map(|()| None)
})
.await;
if let Some(guard) = guard {
drop(set);
return Ok(guard);
}
}
}
fn store(&self, value: T) -> &T {
let stored = self.value.get_or_init(|| value);
self.ready.notify(usize::MAX);
stored
}
}
impl<T> Default for OnceCell<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> From<T> for OnceCell<T> {
fn from(value: T) -> Self {
Self {
value: OnceLock::from(value),
initializing: Mutex::new(()),
ready: Event::new(),
}
}
}
impl<T> fmt::Debug for OnceCell<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = f.debug_tuple("OnceCell");
match self.value.get() {
Some(value) => s.field(value),
None => s.field(&format_args!("<uninit>")),
};
s.finish()
}
}