1use std::{
2 cell::UnsafeCell,
3 panic::{RefUnwindSafe, UnwindSafe},
4 sync::atomic::{AtomicU8, Ordering},
5};
6
7pub(crate) struct OnceCell<T> {
8 state: AtomicU8,
9 value: UnsafeCell<Option<T>>,
10}
11
12const INCOMPLETE: u8 = 0x0;
13const RUNNING: u8 = 0x1;
14const COMPLETE: u8 = 0x2;
15
16unsafe impl<T: Sync + Send> Sync for OnceCell<T> {}
22unsafe impl<T: Send> Send for OnceCell<T> {}
23
24impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceCell<T> {}
25impl<T: UnwindSafe> UnwindSafe for OnceCell<T> {}
26
27impl<T> OnceCell<T> {
28 pub(crate) const fn new() -> OnceCell<T> {
29 OnceCell { state: AtomicU8::new(INCOMPLETE), value: UnsafeCell::new(None) }
30 }
31
32 pub(crate) const fn with_value(value: T) -> OnceCell<T> {
33 OnceCell { state: AtomicU8::new(COMPLETE), value: UnsafeCell::new(Some(value)) }
34 }
35
36 #[inline]
38 pub(crate) fn is_initialized(&self) -> bool {
39 self.state.load(Ordering::Acquire) == COMPLETE
40 }
41
42 #[cold]
45 pub(crate) fn initialize<F, E>(&self, f: F) -> Result<(), E>
46 where
47 F: FnOnce() -> Result<T, E>,
48 {
49 let mut f = Some(f);
50 let mut res: Result<(), E> = Ok(());
51 let slot: *mut Option<T> = self.value.get();
52 initialize_inner(&self.state, &mut || {
53 let f = unsafe { f.take().unwrap_unchecked() };
62 match f() {
63 Ok(value) => unsafe {
64 debug_assert!((*slot).is_none());
67 *slot = Some(value);
68 true
69 },
70 Err(err) => {
71 res = Err(err);
72 false
73 }
74 }
75 });
76 res
77 }
78
79 #[cold]
80 pub(crate) fn wait(&self) {
81 let key = &self.state as *const _ as usize;
82 unsafe {
83 while self.state.load(Ordering::Acquire) != COMPLETE {
84 parking_lot_core::park(
85 key,
86 || self.state.load(Ordering::Acquire) != COMPLETE,
87 || (),
88 |_, _| (),
89 parking_lot_core::DEFAULT_PARK_TOKEN,
90 None,
91 );
92 }
93 }
94 }
95
96 pub(crate) unsafe fn get_unchecked(&self) -> &T {
104 debug_assert!(self.is_initialized());
105 let slot = &*self.value.get();
106 slot.as_ref().unwrap_unchecked()
107 }
108
109 pub(crate) fn get_mut(&mut self) -> Option<&mut T> {
112 let slot: &mut Option<T> = unsafe { &mut *self.value.get() };
114 slot.as_mut()
115 }
116
117 pub(crate) fn into_inner(self) -> Option<T> {
120 self.value.into_inner()
121 }
122}
123
124struct Guard<'a> {
125 state: &'a AtomicU8,
126 new_state: u8,
127}
128
129impl<'a> Drop for Guard<'a> {
130 fn drop(&mut self) {
131 self.state.store(self.new_state, Ordering::Release);
132 unsafe {
133 let key = self.state as *const AtomicU8 as usize;
134 parking_lot_core::unpark_all(key, parking_lot_core::DEFAULT_UNPARK_TOKEN);
135 }
136 }
137}
138
139#[inline(never)]
141fn initialize_inner(state: &AtomicU8, init: &mut dyn FnMut() -> bool) {
142 loop {
143 let exchange =
144 state.compare_exchange_weak(INCOMPLETE, RUNNING, Ordering::Acquire, Ordering::Acquire);
145 match exchange {
146 Ok(_) => {
147 let mut guard = Guard { state, new_state: INCOMPLETE };
148 if init() {
149 guard.new_state = COMPLETE;
150 }
151 return;
152 }
153 Err(COMPLETE) => return,
154 Err(RUNNING) => unsafe {
155 let key = state as *const AtomicU8 as usize;
156 parking_lot_core::park(
157 key,
158 || state.load(Ordering::Relaxed) == RUNNING,
159 || (),
160 |_, _| (),
161 parking_lot_core::DEFAULT_PARK_TOKEN,
162 None,
163 );
164 },
165 Err(INCOMPLETE) => (),
166 Err(_) => debug_assert!(false),
167 }
168 }
169}
170
171#[test]
172fn test_size() {
173 use std::mem::size_of;
174
175 assert_eq!(size_of::<OnceCell<bool>>(), 1 * size_of::<bool>() + size_of::<u8>());
176}