• 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://doc.rust-lang.org/std/lazy/struct.SyncLazy.html>
5 
6 use crate::{once::Once, RelaxStrategy, Spin};
7 use core::{cell::Cell, fmt, ops::Deref};
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, R = Spin> {
42     cell: Once<T, R>,
43     init: Cell<Option<F>>,
44 }
45 
46 impl<T: fmt::Debug, F, R> fmt::Debug for Lazy<T, F, R> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result47     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48         f.debug_struct("Lazy")
49             .field("cell", &self.cell)
50             .field("init", &"..")
51             .finish()
52     }
53 }
54 
55 // We never create a `&F` from a `&Lazy<T, F>` so it is fine
56 // to not impl `Sync` for `F`
57 // we do create a `&mut Option<F>` in `force`, but this is
58 // properly synchronized, so it only happens once
59 // so it also does not contribute to this impl.
60 unsafe impl<T, F: Send> Sync for Lazy<T, F> where Once<T>: Sync {}
61 // auto-derived `Send` impl is OK.
62 
63 impl<T, F, R> Lazy<T, F, R> {
64     /// Creates a new lazy value with the given initializing
65     /// function.
new(f: F) -> Self66     pub const fn new(f: F) -> Self {
67         Self {
68             cell: Once::new(),
69             init: Cell::new(Some(f)),
70         }
71     }
72     /// Retrieves a mutable pointer to the inner data.
73     ///
74     /// This is especially useful when interfacing with low level code or FFI where the caller
75     /// explicitly knows that it has exclusive access to the inner data. Note that reading from
76     /// this pointer is UB until initialized or directly written to.
as_mut_ptr(&self) -> *mut T77     pub fn as_mut_ptr(&self) -> *mut T {
78         self.cell.as_mut_ptr()
79     }
80 }
81 
82 impl<T, F: FnOnce() -> T, R: RelaxStrategy> Lazy<T, F, R> {
83     /// Forces the evaluation of this lazy value and
84     /// returns a reference to result. This is equivalent
85     /// to the `Deref` impl, but is explicit.
86     ///
87     /// # Examples
88     ///
89     /// ```
90     /// use spin::Lazy;
91     ///
92     /// let lazy = Lazy::new(|| 92);
93     ///
94     /// assert_eq!(Lazy::force(&lazy), &92);
95     /// assert_eq!(&*lazy, &92);
96     /// ```
force(this: &Self) -> &T97     pub fn force(this: &Self) -> &T {
98         this.cell.call_once(|| match this.init.take() {
99             Some(f) => f(),
100             None => panic!("Lazy instance has previously been poisoned"),
101         })
102     }
103 }
104 
105 impl<T, F: FnOnce() -> T, R: RelaxStrategy> Deref for Lazy<T, F, R> {
106     type Target = T;
107 
deref(&self) -> &T108     fn deref(&self) -> &T {
109         Self::force(self)
110     }
111 }
112 
113 impl<T: Default, R> Default for Lazy<T, fn() -> T, R> {
114     /// Creates a new lazy value using `Default` as the initializing function.
default() -> Self115     fn default() -> Self {
116         Self::new(T::default)
117     }
118 }
119