@@ -8,8 +8,14 @@ use crate::sync::Once;
8
8
/// A synchronization primitive which can 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
///
@@ -37,6 +43,56 @@ use crate::sync::Once;
37
43
/// Some(&12345),
38
44
/// );
39
45
/// ```
46
+ ///
47
+ /// You can use `OnceLock` to implement a type that requires "append-only" logic:
48
+ ///
49
+ /// ```
50
+ /// #![feature(once_cell_try_insert)]
51
+ /// use std::sync::{OnceLock, atomic::{AtomicU32, Ordering}};
52
+ /// use std::thread;
53
+ ///
54
+ /// struct OnceList<T> {
55
+ /// data: OnceLock<T>,
56
+ /// next: OnceLock<Box<OnceList<T>>>,
57
+ /// }
58
+ /// impl<T> OnceList<T> {
59
+ /// const fn new() -> OnceList<T> {
60
+ /// OnceList { data: OnceLock::new(), next: OnceLock::new() }
61
+ /// }
62
+ /// fn push(&self, value: T) {
63
+ /// // FIXME: this impl is concise, but is also slow for long lists or many threads.
64
+ /// // as an exercise, consider how you might improve on it while preserving the behavior
65
+ /// if let Err((_, value)) = self.data.try_insert(value) {
66
+ /// let next = self.next.get_or_init(|| Box::new(OnceList::new()));
67
+ /// next.push(value)
68
+ /// };
69
+ /// }
70
+ /// fn contains(&self, example: &T) -> bool
71
+ /// where
72
+ /// T: PartialEq,
73
+ /// {
74
+ /// self.data.get().map(|item| item == example).filter(|v| *v).unwrap_or_else(|| {
75
+ /// self.next.get().map(|next| next.contains(example)).unwrap_or(false)
76
+ /// })
77
+ /// }
78
+ /// }
79
+ ///
80
+ /// // Let's exercise this new Sync append-only list by doing a little counting
81
+ /// static LIST: OnceList<u32> = OnceList::new();
82
+ /// static COUNTER: AtomicU32 = AtomicU32::new(0);
83
+ ///
84
+ /// let vec = (0..thread::available_parallelism().unwrap().get()).map(|_| thread::spawn(|| {
85
+ /// while let i @ 0..1000 = COUNTER.fetch_add(1, Ordering::Relaxed) {
86
+ /// LIST.push(i);
87
+ /// }
88
+ /// })).collect::<Vec<thread::JoinHandle<_>>>();
89
+ /// vec.into_iter().for_each(|handle| handle.join().unwrap());
90
+ ///
91
+ /// for i in 0..1000 {
92
+ /// assert!(LIST.contains(&i));
93
+ /// }
94
+ ///
95
+ /// ```
40
96
#[ stable( feature = "once_cell" , since = "1.70.0" ) ]
41
97
pub struct OnceLock < T > {
42
98
once : Once ,
0 commit comments