Rollup merge of #125696 - workingjubilee:please-dont-say-you-are-lazy… · model-checking/verify-rust-std@e38c13a (original) (raw)
`@@ -8,47 +8,17 @@ use crate::sync::Once;
`
8
8
`/// A synchronization primitive which can nominally be written to only once.
`
9
9
`///
`
10
10
`` /// This type is a thread-safe [OnceCell
], and can be used in statics.
``
``
11
`` +
/// In many simple cases, you can use [LazyLock<T, F>
] instead to get the benefits of this type
``
``
12
`` +
/// with less effort: LazyLock<T, F>
"looks like" &T
because it initializes with F
on deref!
``
``
13
`+
/// Where OnceLock shines is when LazyLock is too simple to support a given case, as LazyLock
`
``
14
`` +
/// doesn't allow additional inputs to its function after you call [LazyLock::new(|| ...)
].
``
11
15
`///
`
12
16
`` /// [OnceCell
]: crate::cell::OnceCell
``
``
17
`` +
/// [LazyLock<T, F>
]: crate::sync::LazyLock
``
``
18
`` +
/// [LazyLock::new(|| ...)
]: crate::sync::LazyLock::new
``
13
19
`///
`
14
20
`/// # Examples
`
15
21
`///
`
16
``
`` -
/// Using OnceLock
to store a function’s previously computed value (a.k.a.
``
17
``
`-
/// ‘lazy static’ or ‘memoizing’):
`
18
``
`-
///
`
19
``
/// ```
20
``
`-
/// use std::sync::OnceLock;
`
21
``
`-
///
`
22
``
`-
/// struct DeepThought {
`
23
``
`-
/// answer: String,
`
24
``
`-
/// }
`
25
``
`-
///
`
26
``
`-
/// impl DeepThought {
`
27
``
`-
/// # fn great_question() -> String {
`
28
``
`-
/// # "42".to_string()
`
29
``
`-
/// # }
`
30
``
`-
/// #
`
31
``
`-
/// fn new() -> Self {
`
32
``
`-
/// Self {
`
33
``
`-
/// // M3 Ultra takes about 16 million years in --release config
`
34
``
`-
/// answer: Self::great_question(),
`
35
``
`-
/// }
`
36
``
`-
/// }
`
37
``
`-
/// }
`
38
``
`-
///
`
39
``
`-
/// fn computation() -> &'static DeepThought {
`
40
``
`` -
/// // n.b. static items do not call [Drop
] on program termination, so if
``
41
``
`` -
/// // [DeepThought
] impls Drop, that will not be used for this instance.
``
42
``
`-
/// static COMPUTATION: OnceLock = OnceLock::new();
`
43
``
`-
/// COMPUTATION.get_or_init(|| DeepThought::new())
`
44
``
`-
/// }
`
45
``
`-
///
`
46
``
`` -
/// // The DeepThought
is built, stored in the OnceLock
, and returned.
``
47
``
`-
/// let _ = computation().answer;
`
48
``
`` -
/// // The DeepThought
is retrieved from the OnceLock
and returned.
``
49
``
`-
/// let _ = computation().answer;
`
50
``
/// ```
51
``
`-
///
`
52
22
`` /// Writing to a OnceLock
from a separate thread:
``
53
23
`///
`
54
24
```` /// ```
`@@ -73,6 +43,55 @@ use crate::sync::Once;
`
`73`
`43`
`/// Some(&12345),
`
`74`
`44`
`/// );
`
`75`
`45`
```` /// ```
``
46
`+
///
`
``
47
`` +
/// You can use OnceLock
to implement a type that requires "append-only" logic:
``
``
48
`+
///
`
``
49
/// ```
``
50
`+
/// use std::sync::{OnceLock, atomic::{AtomicU32, Ordering}};
`
``
51
`+
/// use std::thread;
`
``
52
`+
///
`
``
53
`+
/// struct OnceList {
`
``
54
`+
/// data: OnceLock,
`
``
55
`+
/// next: OnceLock<Box<OnceList>>,
`
``
56
`+
/// }
`
``
57
`+
/// impl OnceList {
`
``
58
`+
/// const fn new() -> OnceList {
`
``
59
`+
/// OnceList { data: OnceLock::new(), next: OnceLock::new() }
`
``
60
`+
/// }
`
``
61
`+
/// fn push(&self, value: T) {
`
``
62
`+
/// // FIXME: this impl is concise, but is also slow for long lists or many threads.
`
``
63
`+
/// // as an exercise, consider how you might improve on it while preserving the behavior
`
``
64
`+
/// if let Err(value) = self.data.set(value) {
`
``
65
`+
/// let next = self.next.get_or_init(|| Box::new(OnceList::new()));
`
``
66
`+
/// next.push(value)
`
``
67
`+
/// };
`
``
68
`+
/// }
`
``
69
`+
/// fn contains(&self, example: &T) -> bool
`
``
70
`+
/// where
`
``
71
`+
/// T: PartialEq,
`
``
72
`+
/// {
`
``
73
`+
/// self.data.get().map(|item| item == example).filter(|v| *v).unwrap_or_else(|| {
`
``
74
`+
/// self.next.get().map(|next| next.contains(example)).unwrap_or(false)
`
``
75
`+
/// })
`
``
76
`+
/// }
`
``
77
`+
/// }
`
``
78
`+
///
`
``
79
`+
/// // Let's exercise this new Sync append-only list by doing a little counting
`
``
80
`+
/// static LIST: OnceList = OnceList::new();
`
``
81
`+
/// static COUNTER: AtomicU32 = AtomicU32::new(0);
`
``
82
`+
///
`
``
83
`+
/// let vec = (0..thread::available_parallelism().unwrap().get()).map(|_| thread::spawn(|| {
`
``
84
`+
/// while let i @ 0..=1000 = COUNTER.fetch_add(1, Ordering::Relaxed) {
`
``
85
`+
/// LIST.push(i);
`
``
86
`+
/// }
`
``
87
`+
/// })).collect::<Vec<thread::JoinHandle<_>>>();
`
``
88
`+
/// vec.into_iter().for_each(|handle| handle.join().unwrap());
`
``
89
`+
///
`
``
90
`+
/// for i in 0..=1000 {
`
``
91
`+
/// assert!(LIST.contains(&i));
`
``
92
`+
/// }
`
``
93
`+
///
`
``
94
/// ```
76
95
`#[stable(feature = "once_cell", since = "1.70.0")]
`
77
96
`pub struct OnceLock {
`
78
97
`once: Once,
`