use super::{Semaphore, SemaphorePermit, TryAcquireError};
use crate::loom::cell::UnsafeCell;
use std::error::Error;
use std::fmt;
use std::future::Future;
use std::mem::MaybeUninit;
use std::ops::Drop;
use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};
pub struct OnceCell<T> {
value_set: AtomicBool,
value: UnsafeCell<MaybeUninit<T>>,
semaphore: Semaphore,
}
impl<T> Default for OnceCell<T> {
fn default() -> OnceCell<T> {
OnceCell::new()
}
}
impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("OnceCell")
.field("value", &self.get())
.finish()
}
}
impl<T: Clone> Clone for OnceCell<T> {
fn clone(&self) -> OnceCell<T> {
OnceCell::new_with(self.get().cloned())
}
}
impl<T: PartialEq> PartialEq for OnceCell<T> {
fn eq(&self, other: &OnceCell<T>) -> bool {
self.get() == other.get()
}
}
impl<T: Eq> Eq for OnceCell<T> {}
impl<T> Drop for OnceCell<T> {
fn drop(&mut self) {
if self.initialized_mut() {
unsafe {
self.value
.with_mut(|ptr| ptr::drop_in_place((*ptr).as_mut_ptr()));
};
}
}
}
impl<T> From<T> for OnceCell<T> {
fn from(value: T) -> Self {
OnceCell {
value_set: AtomicBool::new(true),
value: UnsafeCell::new(MaybeUninit::new(value)),
semaphore: Semaphore::new_closed(),
}
}
}
impl<T> OnceCell<T> {
pub fn new() -> Self {
OnceCell {
value_set: AtomicBool::new(false),
value: UnsafeCell::new(MaybeUninit::uninit()),
semaphore: Semaphore::new(1),
}
}
pub fn new_with(value: Option<T>) -> Self {
if let Some(v) = value {
OnceCell::from(v)
} else {
OnceCell::new()
}
}
#[cfg(not(all(loom, test)))]
pub const fn const_new_with(value: T) -> Self {
OnceCell {
value_set: AtomicBool::new(true),
value: UnsafeCell::new(MaybeUninit::new(value)),
semaphore: Semaphore::const_new_closed(),
}
}
#[cfg(not(all(loom, test)))]
pub const fn const_new() -> Self {
OnceCell {
value_set: AtomicBool::new(false),
value: UnsafeCell::new(MaybeUninit::uninit()),
semaphore: Semaphore::const_new(1),
}
}
pub fn initialized(&self) -> bool {
self.value_set.load(Ordering::Acquire)
}
fn initialized_mut(&mut self) -> bool {
*self.value_set.get_mut()
}
unsafe fn get_unchecked(&self) -> &T {
&*self.value.with(|ptr| (*ptr).as_ptr())
}
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
&mut *self.value.with_mut(|ptr| (*ptr).as_mut_ptr())
}
fn set_value(&self, value: T, permit: SemaphorePermit<'_>) -> &T {
unsafe {
self.value.with_mut(|ptr| (*ptr).as_mut_ptr().write(value));
}
self.value_set.store(true, Ordering::Release);
self.semaphore.close();
permit.forget();
unsafe { self.get_unchecked() }
}
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 fn set(&self, value: T) -> Result<(), SetError<T>> {
if self.initialized() {
return Err(SetError::AlreadyInitializedError(value));
}
match self.semaphore.try_acquire() {
Ok(permit) => {
debug_assert!(!self.initialized());
self.set_value(value, permit);
Ok(())
}
Err(TryAcquireError::NoPermits) => {
Err(SetError::InitializingError(value))
}
Err(TryAcquireError::Closed) => {
Err(SetError::AlreadyInitializedError(value))
}
}
}
pub async fn get_or_init<F, Fut>(&self, f: F) -> &T
where
F: FnOnce() -> Fut,
Fut: Future<Output = T>,
{
crate::trace::async_trace_leaf().await;
if self.initialized() {
unsafe { self.get_unchecked() }
} else {
match self.semaphore.acquire().await {
Ok(permit) => {
debug_assert!(!self.initialized());
let value = f().await;
self.set_value(value, permit)
}
Err(_) => {
debug_assert!(self.initialized());
unsafe { self.get_unchecked() }
}
}
}
}
pub async fn get_or_try_init<E, F, Fut>(&self, f: F) -> Result<&T, E>
where
F: FnOnce() -> Fut,
Fut: Future<Output = Result<T, E>>,
{
crate::trace::async_trace_leaf().await;
if self.initialized() {
unsafe { Ok(self.get_unchecked()) }
} else {
match self.semaphore.acquire().await {
Ok(permit) => {
debug_assert!(!self.initialized());
let value = f().await;
match value {
Ok(value) => Ok(self.set_value(value, permit)),
Err(e) => Err(e),
}
}
Err(_) => {
debug_assert!(self.initialized());
unsafe { Ok(self.get_unchecked()) }
}
}
}
}
pub fn into_inner(mut self) -> Option<T> {
if self.initialized_mut() {
*self.value_set.get_mut() = false;
Some(unsafe { self.value.with(|ptr| ptr::read(ptr).assume_init()) })
} else {
None
}
}
pub fn take(&mut self) -> Option<T> {
std::mem::take(self).into_inner()
}
}
unsafe impl<T: Sync + Send> Sync for OnceCell<T> {}
unsafe impl<T: Send> Send for OnceCell<T> {}
#[derive(Debug, PartialEq, Eq)]
pub enum SetError<T> {
AlreadyInitializedError(T),
InitializingError(T),
}
impl<T> fmt::Display for SetError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SetError::AlreadyInitializedError(_) => write!(f, "AlreadyInitializedError"),
SetError::InitializingError(_) => write!(f, "InitializingError"),
}
}
}
impl<T: fmt::Debug> Error for SetError<T> {}
impl<T> SetError<T> {
pub fn is_already_init_err(&self) -> bool {
match self {
SetError::AlreadyInitializedError(_) => true,
SetError::InitializingError(_) => false,
}
}
pub fn is_initializing_err(&self) -> bool {
match self {
SetError::AlreadyInitializedError(_) => false,
SetError::InitializingError(_) => true,
}
}
}