generic_once_cell/
imp.rs

1use core::{
2    panic::{RefUnwindSafe, UnwindSafe},
3    sync::atomic::{AtomicBool, Ordering},
4};
5
6use lock_api::{Mutex, RawMutex};
7
8pub(crate) struct OnceCell<R, T> {
9    initialized: AtomicBool,
10    value: Mutex<R, Option<T>>,
11}
12
13impl<R, T> RefUnwindSafe for OnceCell<R, T>
14where
15    R: RefUnwindSafe + UnwindSafe,
16    T: RefUnwindSafe + UnwindSafe,
17{
18}
19impl<R, T> UnwindSafe for OnceCell<R, T>
20where
21    R: UnwindSafe,
22    T: UnwindSafe,
23{
24}
25
26impl<R: RawMutex, T> OnceCell<R, T> {
27    pub(crate) const fn new() -> Self {
28        Self {
29            initialized: AtomicBool::new(false),
30            value: Mutex::new(None),
31        }
32    }
33
34    pub(crate) const fn with_value(value: T) -> Self {
35        Self {
36            initialized: AtomicBool::new(true),
37            value: Mutex::new(Some(value)),
38        }
39    }
40
41    #[inline]
42    pub(crate) fn is_initialized(&self) -> bool {
43        self.initialized.load(Ordering::Acquire)
44    }
45
46    #[cold]
47    pub(crate) fn initialize<F, E>(&self, f: F) -> Result<(), E>
48    where
49        F: FnOnce() -> Result<T, E>,
50    {
51        let mut guard = self.value.lock();
52        if guard.is_none() {
53            *guard = Some(f()?);
54            self.initialized.store(true, Ordering::Release);
55        }
56        Ok(())
57    }
58
59    /// Get the reference to the underlying value, without checking if the cell
60    /// is initialized.
61    ///
62    /// # Safety
63    ///
64    /// Caller must ensure that the cell is in initialized state, and that
65    /// the contents are acquired by (synchronized to) this thread.
66    pub(crate) unsafe fn get_unchecked(&self) -> &T {
67        debug_assert!(self.is_initialized());
68        // SAFETY: The caller ensures that the value is initialized and access synchronized.
69        unsafe { (*self.value.data_ptr()).as_ref().unwrap_unchecked() }
70    }
71
72    #[inline]
73    pub(crate) fn get_mut(&mut self) -> Option<&mut T> {
74        self.value.get_mut().as_mut()
75    }
76
77    #[inline]
78    pub(crate) fn into_inner(self) -> Option<T> {
79        self.value.into_inner()
80    }
81}