use std::cell::UnsafeCell;
use std::convert::Infallible;
use std::fmt;
use std::mem::MaybeUninit;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use crate::semaphore::Semaphore;
use crate::semaphore::SemaphorePermit;
#[cfg(test)]
mod tests;
pub struct OnceCell<T> {
value_set: AtomicBool,
value: UnsafeCell<MaybeUninit<T>>,
semaphore: Semaphore,
}
unsafe impl<T: Sync + Send> Sync for OnceCell<T> {}
unsafe impl<T: Send> Send for OnceCell<T> {}
impl<T> Default for OnceCell<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> OnceCell<T> {
pub const fn new() -> Self {
Self {
value_set: AtomicBool::new(false),
value: UnsafeCell::new(MaybeUninit::uninit()),
semaphore: Semaphore::new(1),
}
}
pub const fn from_value(value: T) -> Self {
Self {
value_set: AtomicBool::new(true),
value: UnsafeCell::new(MaybeUninit::new(value)),
semaphore: Semaphore::new(1),
}
}
fn initialized(&self) -> bool {
self.value_set.load(Ordering::Acquire)
}
fn initialized_mut(&mut self) -> bool {
*self.value_set.get_mut()
}
pub fn get(&self) -> Option<&T> {
if self.initialized() {
Some(unsafe { self.get_unchecked() })
} else {
None
}
}
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.initialized_mut() {
Some(unsafe { self.get_unchecked_mut() })
} else {
None
}
}
pub async fn get_or_init<F>(&self, init: F) -> &T
where
F: AsyncFnOnce() -> T,
{
match self
.get_or_try_init(async || Ok::<T, Infallible>(init().await))
.await
{
Ok(val) => val,
}
}
pub async fn get_or_try_init<E, F>(&self, init: F) -> Result<&T, E>
where
F: AsyncFnOnce() -> Result<T, E>,
{
if let Some(v) = self.get() {
return Ok(v);
}
let permit = self.semaphore.acquire(1).await;
if let Some(v) = self.get() {
return Ok(v);
}
let value = init().await?;
Ok(self.set_value(value, permit))
}
pub async fn get_mut_or_init<F>(&mut self, init: F) -> &mut T
where
F: AsyncFnOnce() -> T,
{
match self
.get_mut_or_try_init(async || Ok::<T, Infallible>(init().await))
.await
{
Ok(val) => val,
}
}
pub async fn get_mut_or_try_init<E, F>(&mut self, init: F) -> Result<&mut T, E>
where
F: AsyncFnOnce() -> Result<T, E>,
{
if self.initialized_mut() {
return Ok(unsafe { self.get_unchecked_mut() });
}
let value = init().await?;
Ok(self.set_value_mut(value))
}
pub async fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
let mut value = Some(value);
let res = self.get_or_init(async || value.take().unwrap()).await;
match value {
None => Ok(res),
Some(value) => Err((res, value)),
}
}
pub async fn set(&self, value: T) -> Result<(), T> {
match self.try_insert(value).await {
Ok(_) => Ok(()),
Err((_, value)) => Err(value),
}
}
pub fn into_inner(mut self) -> Option<T> {
if self.initialized_mut() {
*self.value_set.get_mut() = false;
Some(unsafe { self.value.get_mut().assume_init_read() })
} else {
None
}
}
pub fn take(&mut self) -> Option<T> {
std::mem::take(self).into_inner()
}
#[inline]
unsafe fn get_unchecked(&self) -> &T {
debug_assert!(self.initialized());
unsafe { (&*self.value.get()).assume_init_ref() }
}
#[inline]
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
debug_assert!(self.initialized_mut());
unsafe { (&mut *self.value.get()).assume_init_mut() }
}
fn set_value(&self, value: T, permit: SemaphorePermit<'_>) -> &T {
let _permit = permit;
let value_ptr = self.value.get();
unsafe { value_ptr.write(MaybeUninit::new(value)) };
self.value_set.store(true, Ordering::Release);
unsafe { self.get_unchecked() }
}
fn set_value_mut(&mut self, value: T) -> &mut T {
let value = self.value.get_mut().write(value);
*self.value_set.get_mut() = true;
value
}
}
impl<T> Drop for OnceCell<T> {
fn drop(&mut self) {
if self.initialized_mut() {
unsafe { self.value.get_mut().assume_init_drop() };
}
}
}
impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_tuple("OnceCell");
match self.get() {
Some(v) => d.field(v),
None => d.field(&format_args!("<uninit>")),
};
d.finish()
}
}
impl<T: Clone> Clone for OnceCell<T> {
fn clone(&self) -> OnceCell<T> {
match self.get() {
Some(v) => OnceCell::from_value(v.clone()),
None => OnceCell::new(),
}
}
}
impl<T> From<T> for OnceCell<T> {
fn from(value: T) -> Self {
OnceCell::from_value(value)
}
}
impl<T: PartialEq> PartialEq for OnceCell<T> {
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
}
impl<T: Eq> Eq for OnceCell<T> {}