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> { |
47 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
48 | f&mut DebugStruct<'_, '_>.debug_struct("Lazy" ) |
49 | .field("cell" , &self.cell) |
50 | .field(name:"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. |
66 | 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. |
77 | 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 | /// ``` |
97 | pub fn force(this: &Self) -> &T { |
98 | this.cell.call_once(|| match this.init.take() { |
99 | Some(f: 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 | |
108 | 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. |
115 | fn default() -> Self { |
116 | Self::new(T::default) |
117 | } |
118 | } |
119 | |