]> git.proxmox.com Git - rustc.git/blame - library/std/src/sync/lazy_lock.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / library / std / src / sync / lazy_lock.rs
CommitLineData
923072b8
FG
1use crate::cell::Cell;
2use crate::fmt;
3use crate::ops::Deref;
4use crate::panic::{RefUnwindSafe, UnwindSafe};
5use 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")]
45pub struct LazyLock<T, F = fn() -> T> {
46 cell: OnceLock<T>,
47 init: Cell<Option<F>>,
48}
49
50impl<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
59impl<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")]
86impl<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")]
94impl<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")]
102impl<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")]
114unsafe 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")]
118impl<T, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> where OnceLock<T>: RefUnwindSafe {}
119#[unstable(feature = "once_cell", issue = "74465")]
120impl<T, F: UnwindSafe> UnwindSafe for LazyLock<T, F> where OnceLock<T>: UnwindSafe {}
121
122#[cfg(test)]
123mod tests;