1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
//! Generic definition and implementation of the [`Lazy`] type.
use core::borrow::Borrow;
use core::convert::AsRef;
use core::fmt;
use core::mem::ManuallyDrop;
use core::ops::Deref;
use core::ptr;
use crate::cell::{Block, OnceCell, Unblock};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Lazy
////////////////////////////////////////////////////////////////////////////////////////////////////
/// A type for lazy initialization of e.g. global static variables, which
/// provides the same functionality as the `lazy_static!` macro.
pub struct Lazy<T, B, F = fn() -> T> {
/// The cell storing the lazily initialized value.
cell: OnceCell<T, B>,
/// The initialization function or closure;
/// this is wrapped in a [`ManuallyDrop`] so that [`FnOnce`] closures can
/// be used as well.
init: ManuallyDrop<F>,
}
/********** impl inherent *************************************************************************/
impl<T, B, F> Lazy<T, B, F> {
/// Creates a new uninitialized [`Lazy`] with the given `init` closure.
///
/// # Examples
///
/// The `init` argument can be a simple function pointer or any [`FnOnce`]
/// closure.
///
/// ```
/// # #[cfg(feature = "std")]
/// use conquer_once::Lazy;
/// # #[cfg(not(feature = "std"))]
/// # use conquer_once::spin::Lazy;
///
/// static LAZY_1: Lazy<Vec<i32>> = Lazy::new(|| vec![1, 2, 3, 4, 5]);
/// static LAZY_2: Lazy<Vec<i32>> = Lazy::new(Vec::<i32>::new);
/// ```
#[inline]
pub const fn new(init: F) -> Self {
Self { cell: OnceCell::uninit(), init: ManuallyDrop::new(init) }
}
/// Returns `true` if the [`Lazy`] has been successfully initialized.
#[inline]
pub fn is_initialized(lazy: &Self) -> bool {
lazy.cell.is_initialized()
}
/// Returns `true` if the [`Lazy`] has been poisoned.
#[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,
{
/// Returns a reference to the already initialized inner value or
/// initializes it first.
///
/// This has the same effect as using the [`Deref`] operator on a [`Lazy`].
///
/// # Panics
///
/// This method panics if the `init` procedure specified during construction
/// panics or if the [`Lazy`] is poisoned.
#[inline]
pub fn get_or_init(lazy: &Self) -> &T {
lazy.cell.get_or_init(|| {
let func = unsafe { ptr::read(&*lazy.init) };
func()
})
}
}
/********** impl AsRef ****************************************************************************/
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 Borrow ***************************************************************************/
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 Debug ****************************************************************************/
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 Display **************************************************************************/
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 Deref ****************************************************************************/
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)
}
}