• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Thread-safe, non-blocking, "first one wins" flavor of `OnceCell`.
2 //!
3 //! If two threads race to initialize a type from the `race` module, they
4 //! don't block, execute initialization function together, but only one of
5 //! them stores the result.
6 //!
7 //! This module does not require `std` feature.
8 
9 #[cfg(feature = "atomic-polyfill")]
10 use atomic_polyfill as atomic;
11 #[cfg(not(feature = "atomic-polyfill"))]
12 use core::sync::atomic;
13 
14 use atomic::{AtomicUsize, Ordering};
15 use core::num::NonZeroUsize;
16 
17 /// A thread-safe cell which can be written to only once.
18 #[derive(Default, Debug)]
19 pub struct OnceNonZeroUsize {
20     inner: AtomicUsize,
21 }
22 
23 impl OnceNonZeroUsize {
24     /// Creates a new empty cell.
25     #[inline]
new() -> OnceNonZeroUsize26     pub const fn new() -> OnceNonZeroUsize {
27         OnceNonZeroUsize { inner: AtomicUsize::new(0) }
28     }
29 
30     /// Gets the underlying value.
31     #[inline]
get(&self) -> Option<NonZeroUsize>32     pub fn get(&self) -> Option<NonZeroUsize> {
33         let val = self.inner.load(Ordering::Acquire);
34         NonZeroUsize::new(val)
35     }
36 
37     /// Sets the contents of this cell to `value`.
38     ///
39     /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
40     /// full.
41     #[inline]
set(&self, value: NonZeroUsize) -> Result<(), ()>42     pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> {
43         let exchange =
44             self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire);
45         match exchange {
46             Ok(_) => Ok(()),
47             Err(_) => Err(()),
48         }
49     }
50 
51     /// Gets the contents of the cell, initializing it with `f` if the cell was
52     /// empty.
53     ///
54     /// If several threads concurrently run `get_or_init`, more than one `f` can
55     /// be called. However, all threads will return the same value, produced by
56     /// some `f`.
get_or_init<F>(&self, f: F) -> NonZeroUsize where F: FnOnce() -> NonZeroUsize,57     pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize
58     where
59         F: FnOnce() -> NonZeroUsize,
60     {
61         enum Void {}
62         match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) {
63             Ok(val) => val,
64             Err(void) => match void {},
65         }
66     }
67 
68     /// Gets the contents of the cell, initializing it with `f` if
69     /// the cell was empty. If the cell was empty and `f` failed, an
70     /// error is returned.
71     ///
72     /// If several threads concurrently run `get_or_init`, more than one `f` can
73     /// be called. However, all threads will return the same value, produced by
74     /// some `f`.
get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E> where F: FnOnce() -> Result<NonZeroUsize, E>,75     pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E>
76     where
77         F: FnOnce() -> Result<NonZeroUsize, E>,
78     {
79         let val = self.inner.load(Ordering::Acquire);
80         let res = match NonZeroUsize::new(val) {
81             Some(it) => it,
82             None => {
83                 let mut val = f()?.get();
84                 let exchange =
85                     self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire);
86                 if let Err(old) = exchange {
87                     val = old;
88                 }
89                 unsafe { NonZeroUsize::new_unchecked(val) }
90             }
91         };
92         Ok(res)
93     }
94 }
95 
96 /// A thread-safe cell which can be written to only once.
97 #[derive(Default, Debug)]
98 pub struct OnceBool {
99     inner: OnceNonZeroUsize,
100 }
101 
102 impl OnceBool {
103     /// Creates a new empty cell.
104     #[inline]
new() -> OnceBool105     pub const fn new() -> OnceBool {
106         OnceBool { inner: OnceNonZeroUsize::new() }
107     }
108 
109     /// Gets the underlying value.
110     #[inline]
get(&self) -> Option<bool>111     pub fn get(&self) -> Option<bool> {
112         self.inner.get().map(OnceBool::from_usize)
113     }
114 
115     /// Sets the contents of this cell to `value`.
116     ///
117     /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
118     /// full.
119     #[inline]
set(&self, value: bool) -> Result<(), ()>120     pub fn set(&self, value: bool) -> Result<(), ()> {
121         self.inner.set(OnceBool::to_usize(value))
122     }
123 
124     /// Gets the contents of the cell, initializing it with `f` if the cell was
125     /// empty.
126     ///
127     /// If several threads concurrently run `get_or_init`, more than one `f` can
128     /// be called. However, all threads will return the same value, produced by
129     /// some `f`.
get_or_init<F>(&self, f: F) -> bool where F: FnOnce() -> bool,130     pub fn get_or_init<F>(&self, f: F) -> bool
131     where
132         F: FnOnce() -> bool,
133     {
134         OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f())))
135     }
136 
137     /// Gets the contents of the cell, initializing it with `f` if
138     /// the cell was empty. If the cell was empty and `f` failed, an
139     /// error is returned.
140     ///
141     /// If several threads concurrently run `get_or_init`, more than one `f` can
142     /// be called. However, all threads will return the same value, produced by
143     /// some `f`.
get_or_try_init<F, E>(&self, f: F) -> Result<bool, E> where F: FnOnce() -> Result<bool, E>,144     pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E>
145     where
146         F: FnOnce() -> Result<bool, E>,
147     {
148         self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize)
149     }
150 
151     #[inline]
from_usize(value: NonZeroUsize) -> bool152     fn from_usize(value: NonZeroUsize) -> bool {
153         value.get() == 1
154     }
155     #[inline]
to_usize(value: bool) -> NonZeroUsize156     fn to_usize(value: bool) -> NonZeroUsize {
157         unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) }
158     }
159 }
160 
161 #[cfg(feature = "alloc")]
162 pub use self::once_box::OnceBox;
163 
164 #[cfg(feature = "alloc")]
165 mod once_box {
166     use super::atomic::{AtomicPtr, Ordering};
167     use core::{marker::PhantomData, ptr};
168 
169     use alloc::boxed::Box;
170 
171     /// A thread-safe cell which can be written to only once.
172     pub struct OnceBox<T> {
173         inner: AtomicPtr<T>,
174         ghost: PhantomData<Option<Box<T>>>,
175     }
176 
177     impl<T> core::fmt::Debug for OnceBox<T> {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result178         fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
179             write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed))
180         }
181     }
182 
183     impl<T> Default for OnceBox<T> {
default() -> Self184         fn default() -> Self {
185             Self::new()
186         }
187     }
188 
189     impl<T> Drop for OnceBox<T> {
drop(&mut self)190         fn drop(&mut self) {
191             let ptr = *self.inner.get_mut();
192             if !ptr.is_null() {
193                 drop(unsafe { Box::from_raw(ptr) })
194             }
195         }
196     }
197 
198     impl<T> OnceBox<T> {
199         /// Creates a new empty cell.
new() -> OnceBox<T>200         pub const fn new() -> OnceBox<T> {
201             OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
202         }
203 
204         /// Gets a reference to the underlying value.
get(&self) -> Option<&T>205         pub fn get(&self) -> Option<&T> {
206             let ptr = self.inner.load(Ordering::Acquire);
207             if ptr.is_null() {
208                 return None;
209             }
210             Some(unsafe { &*ptr })
211         }
212 
213         /// Sets the contents of this cell to `value`.
214         ///
215         /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
216         /// full.
set(&self, value: Box<T>) -> Result<(), Box<T>>217         pub fn set(&self, value: Box<T>) -> Result<(), Box<T>> {
218             let ptr = Box::into_raw(value);
219             let exchange = self.inner.compare_exchange(
220                 ptr::null_mut(),
221                 ptr,
222                 Ordering::AcqRel,
223                 Ordering::Acquire,
224             );
225             if let Err(_) = exchange {
226                 let value = unsafe { Box::from_raw(ptr) };
227                 return Err(value);
228             }
229             Ok(())
230         }
231 
232         /// Gets the contents of the cell, initializing it with `f` if the cell was
233         /// empty.
234         ///
235         /// If several threads concurrently run `get_or_init`, more than one `f` can
236         /// be called. However, all threads will return the same value, produced by
237         /// some `f`.
get_or_init<F>(&self, f: F) -> &T where F: FnOnce() -> Box<T>,238         pub fn get_or_init<F>(&self, f: F) -> &T
239         where
240             F: FnOnce() -> Box<T>,
241         {
242             enum Void {}
243             match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) {
244                 Ok(val) => val,
245                 Err(void) => match void {},
246             }
247         }
248 
249         /// Gets the contents of the cell, initializing it with `f` if
250         /// the cell was empty. If the cell was empty and `f` failed, an
251         /// error is returned.
252         ///
253         /// If several threads concurrently run `get_or_init`, more than one `f` can
254         /// be called. However, all threads will return the same value, produced by
255         /// some `f`.
get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result<Box<T>, E>,256         pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
257         where
258             F: FnOnce() -> Result<Box<T>, E>,
259         {
260             let mut ptr = self.inner.load(Ordering::Acquire);
261 
262             if ptr.is_null() {
263                 let val = f()?;
264                 ptr = Box::into_raw(val);
265                 let exchange = self.inner.compare_exchange(
266                     ptr::null_mut(),
267                     ptr,
268                     Ordering::AcqRel,
269                     Ordering::Acquire,
270                 );
271                 if let Err(old) = exchange {
272                     drop(unsafe { Box::from_raw(ptr) });
273                     ptr = old;
274                 }
275             };
276             Ok(unsafe { &*ptr })
277         }
278     }
279 
280     unsafe impl<T: Sync + Send> Sync for OnceBox<T> {}
281 
282     /// ```compile_fail
283     /// struct S(*mut ());
284     /// unsafe impl Sync for S {}
285     ///
286     /// fn share<T: Sync>(_: &T) {}
287     /// share(&once_cell::race::OnceBox::<S>::new());
288     /// ```
_dummy()289     fn _dummy() {}
290 }
291