• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Synchronization primitives for lazy evaluation.
2 //!
3 //! Implementation adapted from the `SyncLazy` type of the standard library. See:
4 //! https://github.com/rust-lang/rust/blob/cae8bc1f2324e31c98cb32b8ed37032fc9cef405/library/std/src/lazy.rs
5 
6 use core::{cell::Cell, fmt, ops::Deref};
7 use crate::Once;
8 
9 /// A value which is initialized on the first access.
10 ///
11 /// This type is a thread-safe `Lazy`, and can be used in statics.
12 ///
13 /// # Examples
14 ///
15 /// ```
16 /// use std::collections::HashMap;
17 /// use spin::Lazy;
18 ///
19 /// static HASHMAP: Lazy<HashMap<i32, String>> = Lazy::new(|| {
20 ///     println!("initializing");
21 ///     let mut m = HashMap::new();
22 ///     m.insert(13, "Spica".to_string());
23 ///     m.insert(74, "Hoyten".to_string());
24 ///     m
25 /// });
26 ///
27 /// fn main() {
28 ///     println!("ready");
29 ///     std::thread::spawn(|| {
30 ///         println!("{:?}", HASHMAP.get(&13));
31 ///     }).join().unwrap();
32 ///     println!("{:?}", HASHMAP.get(&74));
33 ///
34 ///     // Prints:
35 ///     //   ready
36 ///     //   initializing
37 ///     //   Some("Spica")
38 ///     //   Some("Hoyten")
39 /// }
40 /// ```
41 pub struct Lazy<T, F = fn() -> T> {
42     cell: Once<T>,
43     init: Cell<Option<F>>,
44 }
45 
46 impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result47     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48         f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish()
49     }
50 }
51 
52 // We never create a `&F` from a `&Lazy<T, F>` so it is fine
53 // to not impl `Sync` for `F`
54 // we do create a `&mut Option<F>` in `force`, but this is
55 // properly synchronized, so it only happens once
56 // so it also does not contribute to this impl.
57 unsafe impl<T, F: Send> Sync for Lazy<T, F> where Once<T>: Sync {}
58 // auto-derived `Send` impl is OK.
59 
60 impl<T, F> Lazy<T, F> {
61     /// Creates a new lazy value with the given initializing
62     /// function.
new(f: F) -> Lazy<T, F>63     pub const fn new(f: F) -> Lazy<T, F> {
64         Lazy { cell: Once::new(), init: Cell::new(Some(f)) }
65     }
66 }
67 
68 impl<T, F: FnOnce() -> T> Lazy<T, F> {
69     /// Forces the evaluation of this lazy value and
70     /// returns a reference to result. This is equivalent
71     /// to the `Deref` impl, but is explicit.
72     ///
73     /// # Examples
74     ///
75     /// ```
76     /// use spin::Lazy;
77     ///
78     /// let lazy = Lazy::new(|| 92);
79     ///
80     /// assert_eq!(Lazy::force(&lazy), &92);
81     /// assert_eq!(&*lazy, &92);
82     /// ```
force(this: &Lazy<T, F>) -> &T83     pub fn force(this: &Lazy<T, F>) -> &T {
84         this.cell.call_once(|| match this.init.take() {
85             Some(f) => f(),
86             None => panic!("Lazy instance has previously been poisoned"),
87         })
88     }
89 }
90 
91 impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
92     type Target = T;
deref(&self) -> &T93     fn deref(&self) -> &T {
94         Lazy::force(self)
95     }
96 }
97 
98 impl<T: Default> Default for Lazy<T> {
99     /// Creates a new lazy value using `Default` as the initializing function.
default() -> Lazy<T>100     fn default() -> Lazy<T> {
101         Lazy::new(T::default)
102     }
103 }
104