#[cfg(feature = "parking_lot")]
#[path = "imp_pl.rs"]
mod imp;
#[cfg(not(feature = "parking_lot"))]
#[path = "imp_std.rs"]
mod imp;
pub mod unsync {
use std::{
fmt,
ops::Deref,
cell::UnsafeCell,
panic::{UnwindSafe, RefUnwindSafe},
hint::unreachable_unchecked
};
pub struct OnceCell<T> {
inner: UnsafeCell<Option<T>>,
}
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceCell<T> {}
impl<T: UnwindSafe> UnwindSafe for OnceCell<T> {}
impl<T> Default for OnceCell<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.get() {
Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
None => f.write_str("OnceCell(Uninit)"),
}
}
}
impl<T: Clone> Clone for OnceCell<T> {
fn clone(&self) -> OnceCell<T> {
let res = OnceCell::new();
if let Some(value) = self.get() {
match res.set(value.clone()) {
Ok(()) => (),
Err(_) => unreachable!(),
}
}
res
}
}
impl<T: PartialEq> PartialEq for OnceCell<T> {
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
}
impl<T> From<T> for OnceCell<T> {
fn from(value: T) -> Self {
OnceCell { inner: UnsafeCell::new(Some(value)) }
}
}
impl<T> OnceCell<T> {
pub const fn new() -> OnceCell<T> {
OnceCell { inner: UnsafeCell::new(None) }
}
pub fn get(&self) -> Option<&T> {
unsafe { &*self.inner.get() }.as_ref()
}
pub fn set(&self, value: T) -> Result<(), T> {
let slot = unsafe { &*self.inner.get() };
if slot.is_some() {
return Err(value);
}
let slot = unsafe { &mut*self.inner.get() };
*slot = Some(value);
Ok(())
}
pub fn get_or_init<F: FnOnce() -> T>(&self, f: F) -> &T {
enum Void {}
match self.get_or_try_init(|| Ok::<T, Void>(f())) {
Ok(val) => val,
Err(void) => match void {},
}
}
pub fn get_or_try_init<F: FnOnce() -> Result<T, E>, E>(&self, f: F) -> Result<&T, E> {
if let Some(val) = self.get() {
return Ok(val);
}
let val = f()?;
assert!(self.set(val).is_ok(), "reentrant init");
Ok(self.get().unwrap())
}
pub fn into_inner(self) -> Option<T> {
self.inner.into_inner()
}
}
#[derive(Debug)]
pub struct Lazy<T, F = fn() -> T> {
cell: OnceCell<T>,
init: UnsafeCell<Option<F>>,
}
impl<T, F> Lazy<T, F> {
pub const fn new(init: F) -> Lazy<T, F> {
Lazy { cell: OnceCell::new(), init: UnsafeCell::new(Some(init)) }
}
}
impl<T, F: FnOnce() -> T> Lazy<T, F> {
pub fn force(this: &Lazy<T, F>) -> &T {
this.cell.get_or_init(|| unsafe {
match (*this.init.get()).take() {
Some(f) => f(),
None => unreachable_unchecked()
}
})
}
}
impl<T, F: Fn() -> T> Deref for Lazy<T, F> {
type Target = T;
fn deref(&self) -> &T {
Lazy::force(self)
}
}
}
pub mod sync {
use crate::imp::OnceCell as Imp;
use std::{
fmt,
cell::UnsafeCell,
hint::unreachable_unchecked
};
pub struct OnceCell<T>(Imp<T>);
impl<T> Default for OnceCell<T> {
fn default() -> OnceCell<T> {
OnceCell::new()
}
}
impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.get() {
Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
None => f.write_str("OnceCell(Uninit)"),
}
}
}
impl<T: Clone> Clone for OnceCell<T> {
fn clone(&self) -> OnceCell<T> {
let res = OnceCell::new();
if let Some(value) = self.get() {
match res.set(value.clone()) {
Ok(()) => (),
Err(_) => unreachable!(),
}
}
res
}
}
impl<T> From<T> for OnceCell<T> {
fn from(value: T) -> Self {
let cell = Self::new();
cell.get_or_init(|| value);
cell
}
}
impl<T: PartialEq> PartialEq for OnceCell<T> {
fn eq(&self, other: &OnceCell<T>) -> bool {
self.get() == other.get()
}
}
impl<T> OnceCell<T> {
pub const fn new() -> OnceCell<T> {
OnceCell(Imp::new())
}
pub fn get(&self) -> Option<&T> {
self.0.get()
}
pub fn set(&self, value: T) -> Result<(), T> {
self.0.set(value)
}
pub fn get_or_init<F: FnOnce() -> T>(&self, f: F) -> &T {
self.0.get_or_init(f)
}
#[cfg(feature = "parking_lot")]
pub fn get_or_try_init<F: FnOnce() -> Result<T, E>, E>(&self, f: F) -> Result<&T, E> {
self.0.get_or_try_init(f)
}
pub fn into_inner(self) -> Option<T> {
self.0.into_inner()
}
}
pub struct Lazy<T, F = fn() -> T> {
cell: OnceCell<T>,
init: UnsafeCell<Option<F>>,
}
impl<T: fmt::Debug, F: fmt::Debug> fmt::Debug for Lazy<T, F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Lazy")
.field("cell", &self.cell)
.field("init", &"..")
.finish()
}
}
unsafe impl<T: Sync, F: Send> Sync for Lazy<T, F> {}
impl<T, F> Lazy<T, F> {
pub const fn new(f: F) -> Lazy<T, F> {
Lazy { cell: OnceCell::new(), init: UnsafeCell::new(Some(f)) }
}
}
impl<T, F: FnOnce() -> T> Lazy<T, F> {
pub fn force(this: &Lazy<T, F>) -> &T {
this.cell.get_or_init(|| unsafe {
match (*this.init.get()).take() {
Some(f) => f(),
None => unreachable_unchecked()
}
})
}
}
impl<T, F: Fn() -> T> ::std::ops::Deref for Lazy<T, F> {
type Target = T;
fn deref(&self) -> &T {
Lazy::force(self)
}
}
}