once_cell/
race.rs

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//! # Atomic orderings
10//!
11//! All types in this module use `Acquire` and `Release`
12//! [atomic orderings](Ordering) for all their operations. While this is not
13//! strictly necessary for types other than `OnceBox`, it is useful for users as
14//! it allows them to be certain that after `get` or `get_or_init` returns on
15//! one thread, any side-effects caused by the setter thread prior to them
16//! calling `set` or `get_or_init` will be made visible to that thread; without
17//! it, it's possible for it to appear as if they haven't happened yet from the
18//! getter thread's perspective. This is an acceptable tradeoff to make since
19//! `Acquire` and `Release` have very little performance overhead on most
20//! architectures versus `Relaxed`.
21
22#[cfg(not(feature = "portable-atomic"))]
23use core::sync::atomic;
24#[cfg(feature = "portable-atomic")]
25use portable_atomic as atomic;
26
27use atomic::{AtomicPtr, AtomicUsize, Ordering};
28use core::cell::UnsafeCell;
29use core::marker::PhantomData;
30use core::num::NonZeroUsize;
31use core::ptr;
32
33/// A thread-safe cell which can be written to only once.
34#[derive(Default, Debug)]
35pub struct OnceNonZeroUsize {
36    inner: AtomicUsize,
37}
38
39impl OnceNonZeroUsize {
40    /// Creates a new empty cell.
41    #[inline]
42    pub const fn new() -> OnceNonZeroUsize {
43        OnceNonZeroUsize { inner: AtomicUsize::new(0) }
44    }
45
46    /// Gets the underlying value.
47    #[inline]
48    pub fn get(&self) -> Option<NonZeroUsize> {
49        let val = self.inner.load(Ordering::Acquire);
50        NonZeroUsize::new(val)
51    }
52
53    /// Sets the contents of this cell to `value`.
54    ///
55    /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
56    /// full.
57    #[inline]
58    pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> {
59        let exchange =
60            self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire);
61        match exchange {
62            Ok(_) => Ok(()),
63            Err(_) => Err(()),
64        }
65    }
66
67    /// Gets the contents of the cell, initializing it with `f` if the cell was
68    /// empty.
69    ///
70    /// If several threads concurrently run `get_or_init`, more than one `f` can
71    /// be called. However, all threads will return the same value, produced by
72    /// some `f`.
73    pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize
74    where
75        F: FnOnce() -> NonZeroUsize,
76    {
77        enum Void {}
78        match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) {
79            Ok(val) => val,
80            Err(void) => match void {},
81        }
82    }
83
84    /// Gets the contents of the cell, initializing it with `f` if
85    /// the cell was empty. If the cell was empty and `f` failed, an
86    /// error is returned.
87    ///
88    /// If several threads concurrently run `get_or_init`, more than one `f` can
89    /// be called. However, all threads will return the same value, produced by
90    /// some `f`.
91    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E>
92    where
93        F: FnOnce() -> Result<NonZeroUsize, E>,
94    {
95        let val = self.inner.load(Ordering::Acquire);
96        match NonZeroUsize::new(val) {
97            Some(it) => Ok(it),
98            None => self.init(f),
99        }
100    }
101
102    #[cold]
103    #[inline(never)]
104    fn init<E>(&self, f: impl FnOnce() -> Result<NonZeroUsize, E>) -> Result<NonZeroUsize, E> {
105        let mut val = f()?.get();
106        let exchange = self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire);
107        if let Err(old) = exchange {
108            val = old;
109        }
110        Ok(unsafe { NonZeroUsize::new_unchecked(val) })
111    }
112}
113
114/// A thread-safe cell which can be written to only once.
115#[derive(Default, Debug)]
116pub struct OnceBool {
117    inner: OnceNonZeroUsize,
118}
119
120impl OnceBool {
121    /// Creates a new empty cell.
122    #[inline]
123    pub const fn new() -> OnceBool {
124        OnceBool { inner: OnceNonZeroUsize::new() }
125    }
126
127    /// Gets the underlying value.
128    #[inline]
129    pub fn get(&self) -> Option<bool> {
130        self.inner.get().map(OnceBool::from_usize)
131    }
132
133    /// Sets the contents of this cell to `value`.
134    ///
135    /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
136    /// full.
137    #[inline]
138    pub fn set(&self, value: bool) -> Result<(), ()> {
139        self.inner.set(OnceBool::to_usize(value))
140    }
141
142    /// Gets the contents of the cell, initializing it with `f` if the cell was
143    /// empty.
144    ///
145    /// If several threads concurrently run `get_or_init`, more than one `f` can
146    /// be called. However, all threads will return the same value, produced by
147    /// some `f`.
148    pub fn get_or_init<F>(&self, f: F) -> bool
149    where
150        F: FnOnce() -> bool,
151    {
152        OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f())))
153    }
154
155    /// Gets the contents of the cell, initializing it with `f` if
156    /// the cell was empty. If the cell was empty and `f` failed, an
157    /// error is returned.
158    ///
159    /// If several threads concurrently run `get_or_init`, more than one `f` can
160    /// be called. However, all threads will return the same value, produced by
161    /// some `f`.
162    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E>
163    where
164        F: FnOnce() -> Result<bool, E>,
165    {
166        self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize)
167    }
168
169    #[inline]
170    fn from_usize(value: NonZeroUsize) -> bool {
171        value.get() == 1
172    }
173
174    #[inline]
175    fn to_usize(value: bool) -> NonZeroUsize {
176        unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) }
177    }
178}
179
180/// A thread-safe cell which can be written to only once.
181pub struct OnceRef<'a, T> {
182    inner: AtomicPtr<T>,
183    ghost: PhantomData<UnsafeCell<&'a T>>,
184}
185
186// TODO: Replace UnsafeCell with SyncUnsafeCell once stabilized
187unsafe impl<'a, T: Sync> Sync for OnceRef<'a, T> {}
188
189impl<'a, T> core::fmt::Debug for OnceRef<'a, T> {
190    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
191        write!(f, "OnceRef({:?})", self.inner)
192    }
193}
194
195impl<'a, T> Default for OnceRef<'a, T> {
196    fn default() -> Self {
197        Self::new()
198    }
199}
200
201impl<'a, T> OnceRef<'a, T> {
202    /// Creates a new empty cell.
203    pub const fn new() -> OnceRef<'a, T> {
204        OnceRef { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
205    }
206
207    /// Gets a reference to the underlying value.
208    pub fn get(&self) -> Option<&'a T> {
209        let ptr = self.inner.load(Ordering::Acquire);
210        unsafe { ptr.as_ref() }
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.
217    pub fn set(&self, value: &'a T) -> Result<(), ()> {
218        let ptr = value as *const T as *mut T;
219        let exchange =
220            self.inner.compare_exchange(ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire);
221        match exchange {
222            Ok(_) => Ok(()),
223            Err(_) => Err(()),
224        }
225    }
226
227    /// Gets the contents of the cell, initializing it with `f` if the cell was
228    /// empty.
229    ///
230    /// If several threads concurrently run `get_or_init`, more than one `f` can
231    /// be called. However, all threads will return the same value, produced by
232    /// some `f`.
233    pub fn get_or_init<F>(&self, f: F) -> &'a T
234    where
235        F: FnOnce() -> &'a T,
236    {
237        enum Void {}
238        match self.get_or_try_init(|| Ok::<&'a T, Void>(f())) {
239            Ok(val) => val,
240            Err(void) => match void {},
241        }
242    }
243
244    /// Gets the contents of the cell, initializing it with `f` if
245    /// the cell was empty. If the cell was empty and `f` failed, an
246    /// error is returned.
247    ///
248    /// If several threads concurrently run `get_or_init`, more than one `f` can
249    /// be called. However, all threads will return the same value, produced by
250    /// some `f`.
251    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&'a T, E>
252    where
253        F: FnOnce() -> Result<&'a T, E>,
254    {
255        let mut ptr = self.inner.load(Ordering::Acquire);
256
257        if ptr.is_null() {
258            // TODO replace with `cast_mut` when MSRV reaches 1.65.0 (also in `set`)
259            ptr = f()? as *const T as *mut T;
260            let exchange = self.inner.compare_exchange(
261                ptr::null_mut(),
262                ptr,
263                Ordering::AcqRel,
264                Ordering::Acquire,
265            );
266            if let Err(old) = exchange {
267                ptr = old;
268            }
269        }
270
271        Ok(unsafe { &*ptr })
272    }
273
274    /// ```compile_fail
275    /// use once_cell::race::OnceRef;
276    ///
277    /// let mut l = OnceRef::new();
278    ///
279    /// {
280    ///     let y = 2;
281    ///     let mut r = OnceRef::new();
282    ///     r.set(&y).unwrap();
283    ///     core::mem::swap(&mut l, &mut r);
284    /// }
285    ///
286    /// // l now contains a dangling reference to y
287    /// eprintln!("uaf: {}", l.get().unwrap());
288    /// ```
289    fn _dummy() {}
290}
291
292#[cfg(feature = "alloc")]
293pub use self::once_box::OnceBox;
294
295#[cfg(feature = "alloc")]
296mod once_box {
297    use super::atomic::{AtomicPtr, Ordering};
298    use core::{marker::PhantomData, ptr};
299
300    use alloc::boxed::Box;
301
302    /// A thread-safe cell which can be written to only once.
303    pub struct OnceBox<T> {
304        inner: AtomicPtr<T>,
305        ghost: PhantomData<Option<Box<T>>>,
306    }
307
308    impl<T> core::fmt::Debug for OnceBox<T> {
309        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
310            write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed))
311        }
312    }
313
314    impl<T> Default for OnceBox<T> {
315        fn default() -> Self {
316            Self::new()
317        }
318    }
319
320    impl<T> Drop for OnceBox<T> {
321        fn drop(&mut self) {
322            let ptr = *self.inner.get_mut();
323            if !ptr.is_null() {
324                drop(unsafe { Box::from_raw(ptr) })
325            }
326        }
327    }
328
329    impl<T> OnceBox<T> {
330        /// Creates a new empty cell.
331        pub const fn new() -> OnceBox<T> {
332            OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
333        }
334
335        /// Gets a reference to the underlying value.
336        pub fn get(&self) -> Option<&T> {
337            let ptr = self.inner.load(Ordering::Acquire);
338            if ptr.is_null() {
339                return None;
340            }
341            Some(unsafe { &*ptr })
342        }
343
344        /// Sets the contents of this cell to `value`.
345        ///
346        /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
347        /// full.
348        pub fn set(&self, value: Box<T>) -> Result<(), Box<T>> {
349            let ptr = Box::into_raw(value);
350            let exchange = self.inner.compare_exchange(
351                ptr::null_mut(),
352                ptr,
353                Ordering::AcqRel,
354                Ordering::Acquire,
355            );
356            if exchange.is_err() {
357                let value = unsafe { Box::from_raw(ptr) };
358                return Err(value);
359            }
360            Ok(())
361        }
362
363        /// Gets the contents of the cell, initializing it with `f` if the cell was
364        /// empty.
365        ///
366        /// If several threads concurrently run `get_or_init`, more than one `f` can
367        /// be called. However, all threads will return the same value, produced by
368        /// some `f`.
369        pub fn get_or_init<F>(&self, f: F) -> &T
370        where
371            F: FnOnce() -> Box<T>,
372        {
373            enum Void {}
374            match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) {
375                Ok(val) => val,
376                Err(void) => match void {},
377            }
378        }
379
380        /// Gets the contents of the cell, initializing it with `f` if
381        /// the cell was empty. If the cell was empty and `f` failed, an
382        /// error is returned.
383        ///
384        /// If several threads concurrently run `get_or_init`, more than one `f` can
385        /// be called. However, all threads will return the same value, produced by
386        /// some `f`.
387        pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
388        where
389            F: FnOnce() -> Result<Box<T>, E>,
390        {
391            let mut ptr = self.inner.load(Ordering::Acquire);
392
393            if ptr.is_null() {
394                let val = f()?;
395                ptr = Box::into_raw(val);
396                let exchange = self.inner.compare_exchange(
397                    ptr::null_mut(),
398                    ptr,
399                    Ordering::AcqRel,
400                    Ordering::Acquire,
401                );
402                if let Err(old) = exchange {
403                    drop(unsafe { Box::from_raw(ptr) });
404                    ptr = old;
405                }
406            };
407            Ok(unsafe { &*ptr })
408        }
409    }
410
411    unsafe impl<T: Sync + Send> Sync for OnceBox<T> {}
412
413    /// ```compile_fail
414    /// struct S(*mut ());
415    /// unsafe impl Sync for S {}
416    ///
417    /// fn share<T: Sync>(_: &T) {}
418    /// share(&once_cell::race::OnceBox::<S>::new());
419    /// ```
420    fn _dummy() {}
421}