use core::{borrow::Borrow, convert::AsRef, fmt, mem::ManuallyDrop, ops::Deref, ptr};
use crate::cell::{Block, OnceCell, Unblock};
pub struct Lazy<T, B, F = fn() -> T> {
cell: OnceCell<T, B>,
init: ManuallyDrop<F>,
}
impl<T, B, F> Lazy<T, B, F> {
#[inline]
pub const fn new(init: F) -> Self {
Self { cell: OnceCell::uninit(), init: ManuallyDrop::new(init) }
}
#[inline]
pub fn is_initialized(lazy: &Self) -> bool {
lazy.cell.is_initialized()
}
#[inline]
pub fn is_poisoned(lazy: &Self) -> bool {
lazy.cell.is_poisoned()
}
}
impl<T, B, F> Lazy<T, B, F>
where
B: Block,
F: FnOnce() -> T,
{
#[inline]
pub fn get_or_init(lazy: &Self) -> &T {
lazy.cell.get_or_init(|| {
let func = unsafe { ptr::read(&*lazy.init) };
func()
})
}
}
impl<T, B, F> AsRef<T> for Lazy<T, B, F>
where
B: Block,
F: FnOnce() -> T,
{
#[inline]
fn as_ref(&self) -> &T {
Lazy::get_or_init(self)
}
}
impl<T, B, F> Borrow<T> for Lazy<T, B, F>
where
B: Block,
F: FnOnce() -> T,
{
#[inline]
fn borrow(&self) -> &T {
Lazy::get_or_init(self)
}
}
impl<T, B, F> fmt::Debug for Lazy<T, B, F>
where
T: fmt::Debug,
B: Unblock,
F: FnOnce() -> T,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.cell, f)
}
}
impl<T, B, F> fmt::Display for Lazy<T, B, F>
where
T: fmt::Display,
B: Block,
F: FnOnce() -> T,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(Self::get_or_init(self), f)
}
}
impl<T, B, F> Deref for Lazy<T, B, F>
where
B: Block,
F: FnOnce() -> T,
{
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
Lazy::get_or_init(self)
}
}