/rust/registry/src/index.crates.io-6f17d22bba15001f/spin-0.9.8/src/lazy.rs
Line | Count | Source (jump to first uncovered line) |
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 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
48 | 0 | f.debug_struct("Lazy") |
49 | 0 | .field("cell", &self.cell) |
50 | 0 | .field("init", &"..") |
51 | 0 | .finish() |
52 | 0 | } |
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 | 0 | pub const fn new(f: F) -> Self { |
67 | 0 | Self { |
68 | 0 | cell: Once::new(), |
69 | 0 | init: Cell::new(Some(f)), |
70 | 0 | } |
71 | 0 | } |
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 | 0 | pub fn as_mut_ptr(&self) -> *mut T { |
78 | 0 | self.cell.as_mut_ptr() |
79 | 0 | } |
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 | 0 | pub fn force(this: &Self) -> &T { |
98 | 0 | this.cell.call_once(|| match this.init.take() { |
99 | 0 | Some(f) => f(), |
100 | 0 | None => panic!("Lazy instance has previously been poisoned"), |
101 | 0 | }) |
102 | 0 | } |
103 | | } |
104 | | |
105 | | impl<T, F: FnOnce() -> T, R: RelaxStrategy> Deref for Lazy<T, F, R> { |
106 | | type Target = T; |
107 | | |
108 | 0 | fn deref(&self) -> &T { |
109 | 0 | Self::force(self) |
110 | 0 | } |
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 | 0 | fn default() -> Self { |
116 | 0 | Self::new(T::default) |
117 | 0 | } |
118 | | } |