crossbeam_epoch/sync/
once_lock.rs

1// Based on unstable std::sync::OnceLock.
2//
3// Source: https://github.com/rust-lang/rust/blob/8e9c93df464b7ada3fc7a1c8ccddd9dcb24ee0a0/library/std/src/sync/once_lock.rs
4
5use core::cell::UnsafeCell;
6use core::mem::MaybeUninit;
7use std::sync::Once;
8
9pub(crate) struct OnceLock<T> {
10    once: Once,
11    value: UnsafeCell<MaybeUninit<T>>,
12    // Unlike std::sync::OnceLock, we don't need PhantomData here because
13    // we don't use #[may_dangle].
14}
15
16unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
17unsafe impl<T: Send> Send for OnceLock<T> {}
18
19impl<T> OnceLock<T> {
20    /// Creates a new empty cell.
21    #[must_use]
22    pub(crate) const fn new() -> Self {
23        Self {
24            once: Once::new(),
25            value: UnsafeCell::new(MaybeUninit::uninit()),
26        }
27    }
28
29    /// Gets the contents of the cell, initializing it with `f` if the cell
30    /// was empty.
31    ///
32    /// Many threads may call `get_or_init` concurrently with different
33    /// initializing functions, but it is guaranteed that only one function
34    /// will be executed.
35    ///
36    /// # Panics
37    ///
38    /// If `f` panics, the panic is propagated to the caller, and the cell
39    /// remains uninitialized.
40    ///
41    /// It is an error to reentrantly initialize the cell from `f`. The
42    /// exact outcome is unspecified. Current implementation deadlocks, but
43    /// this may be changed to a panic in the future.
44    pub(crate) fn get_or_init<F>(&self, f: F) -> &T
45    where
46        F: FnOnce() -> T,
47    {
48        // Fast path check
49        if self.once.is_completed() {
50            // SAFETY: The inner value has been initialized
51            return unsafe { self.get_unchecked() };
52        }
53        self.initialize(f);
54
55        // SAFETY: The inner value has been initialized
56        unsafe { self.get_unchecked() }
57    }
58
59    #[cold]
60    fn initialize<F>(&self, f: F)
61    where
62        F: FnOnce() -> T,
63    {
64        let slot = self.value.get();
65
66        self.once.call_once(|| {
67            let value = f();
68            unsafe { slot.write(MaybeUninit::new(value)) }
69        });
70    }
71
72    /// # Safety
73    ///
74    /// The value must be initialized
75    unsafe fn get_unchecked(&self) -> &T {
76        debug_assert!(self.once.is_completed());
77        &*self.value.get().cast::<T>()
78    }
79}
80
81impl<T> Drop for OnceLock<T> {
82    fn drop(&mut self) {
83        if self.once.is_completed() {
84            // SAFETY: The inner value has been initialized
85            unsafe { (*self.value.get()).assume_init_drop() };
86        }
87    }
88}