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 pub(crate) unsafe fn get_unchecked(&self) -> &T {
67 debug_assert!(self.is_initialized());
68 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}