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