simple_lazy/
lib.rs

1use std::cell::Cell;
2use std::ops::Deref;
3use std::panic::RefUnwindSafe;
4use std::sync::OnceLock;
5
6/// A value which is initialized on the first access.
7///
8/// This type is thread-safe and can be used in statics.
9///
10/// # Example
11///
12/// ```
13/// use std::collections::HashMap;
14///
15/// use simple_lazy::Lazy;
16///
17/// static HASHMAP: Lazy<HashMap<i32, String>> = Lazy::new(|| {
18///     println!("initializing");
19///     let mut m = HashMap::new();
20///     m.insert(13, "Spica".to_string());
21///     m.insert(74, "Hoyten".to_string());
22///     m
23/// });
24///
25/// fn main() {
26///     println!("ready");
27///     std::thread::spawn(|| {
28///         println!("{:?}", HASHMAP.get(&13));
29///     }).join().unwrap();
30///     println!("{:?}", HASHMAP.get(&74));
31///
32///     // Prints:
33///     //   ready
34///     //   initializing
35///     //   Some("Spica")
36///     //   Some("Hoyten")
37/// }
38/// ```
39pub struct Lazy<T, F = fn() -> T> {
40    once: OnceLock<T>,
41    init: Cell<Option<F>>,
42}
43
44// We never create a `&F` from a `&Lazy<T, F>` so it is fine to not impl
45// `Sync` for `F`. We do create a `&mut Option<F>` in `force`, but this is
46// properly synchronized, so it only happens once so it also does not
47// contribute to this impl.
48unsafe impl<T, F: Send> Sync for Lazy<T, F> where OnceLock<T>: Sync {}
49// auto-derived `Send` impl is OK.
50
51impl<T, F: RefUnwindSafe> RefUnwindSafe for Lazy<T, F> where OnceLock<T>: RefUnwindSafe {}
52
53impl<T, F> Lazy<T, F> {
54    pub const fn new(init: F) -> Self {
55        Lazy {
56            once: OnceLock::new(),
57            init: Cell::new(Some(init)),
58        }
59    }
60}
61
62impl<T, F: FnOnce() -> T> Lazy<T, F> {
63    /// Forces the evaluation of this lazy value and
64    /// returns a reference to the result. This is equivalent
65    /// to the `Deref` impl, but is explicit.
66    ///
67    /// # Example
68    /// ```
69    /// use simple_lazy::Lazy;
70    ///
71    /// let lazy = Lazy::new(|| 92);
72    ///
73    /// assert_eq!(Lazy::force(&lazy), &92);
74    /// assert_eq!(&*lazy, &92);
75    /// ```
76    pub fn force(this: &Lazy<T, F>) -> &T {
77        this.once.get_or_init(|| match this.init.take() {
78            Some(f) => f(),
79            None => panic!("Lazy instance has previously been poisoned"),
80        })
81    }
82
83    /// Gets the reference to the result of this lazy value if
84    /// it was initialized, otherwise returns `None`.
85    ///
86    /// # Example
87    /// ```
88    /// use simple_lazy::Lazy;
89    ///
90    /// let lazy = Lazy::new(|| 92);
91    ///
92    /// assert_eq!(Lazy::get(&lazy), None);
93    /// assert_eq!(&*lazy, &92);
94    /// assert_eq!(Lazy::get(&lazy), Some(&92));
95    /// ```
96    pub fn get(this: &Lazy<T, F>) -> Option<&T> {
97        this.once.get()
98    }
99}
100
101impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
102    type Target = T;
103    fn deref(&self) -> &T {
104        Lazy::force(self)
105    }
106}
107
108impl<T: Default> Default for Lazy<T> {
109    /// Creates a new lazy value using `Default` as the initializing function.
110    fn default() -> Lazy<T> {
111        Lazy::new(T::default)
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    fn assert_traits<T: Send + Sync + RefUnwindSafe>() {}
120
121    #[test]
122    fn test_lazy() {
123        assert_traits::<Lazy<String>>();
124    }
125}