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
//! 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};

////////////////////////////////////////////////////////////////////////////////////////////////////
// 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.
    ///
    /// ```
    /// use conquer_once::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) }
    }
}

impl<T, B, F> Lazy<T, B, F>
where
    B: Block,
    F: FnOnce() -> T,
{
    /// 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()
    }

    /// 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: Block,
    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)
    }
}