1use core::{
2 cell::UnsafeCell,
3 fmt,
4 marker::PhantomData,
5 mem::MaybeUninit,
6 sync::atomic::{AtomicUsize, Ordering},
7};
8
9const ONCE_STATE_INIT: usize = 0;
10const ONCE_STATE_RUNNING: usize = 1;
11const ONCE_STATE_DONE: usize = 2;
12
13struct Once {
14 state: AtomicUsize,
15}
16
17impl Once {
18 pub const fn new() -> Self {
19 Once {
20 state: AtomicUsize::new(ONCE_STATE_INIT),
21 }
22 }
23
24 #[inline(always)]
25 fn is_completed(&self) -> bool {
26 self.state.load(Ordering::Relaxed) == ONCE_STATE_DONE
27 }
28
29 pub fn call(&self, f: impl FnOnce()) {
30 let mut state = self.state.load(Ordering::Acquire);
31 loop {
32 match state {
33 ONCE_STATE_INIT => {
34 match self.state.compare_exchange_weak(
36 ONCE_STATE_INIT,
37 ONCE_STATE_RUNNING,
38 Ordering::Acquire,
39 Ordering::Relaxed,
40 ) {
41 Ok(_) => {
42 f();
45
46 self.state.store(ONCE_STATE_DONE, Ordering::Release);
48 return;
49 }
50 Err(new) => {
51 state = new;
53 continue;
54 }
55 }
56 }
57 ONCE_STATE_RUNNING => {
58 panic!("Once::call already running");
59 }
60 ONCE_STATE_DONE => return,
61 _ => unreachable!("state is never set to invalid values"),
62 }
63 }
64 }
65}
66
67pub struct OnceLock<T> {
68 once: Once,
69 value: UnsafeCell<MaybeUninit<T>>,
71 _marker: PhantomData<T>,
89}
90
91unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
92unsafe impl<T: Send> Send for OnceLock<T> {}
93
94impl Default for Once {
95 fn default() -> Self {
96 Self::new()
97 }
98}
99
100impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 let mut d = f.debug_tuple("OnceLock");
103 match self.try_get() {
104 Some(v) => d.field(v),
105 None => d.field(&format_args!("<uninit>")),
106 };
107 d.finish()
108 }
109}
110
111impl<T: Clone> Clone for OnceLock<T> {
112 #[inline]
113 fn clone(&self) -> OnceLock<T> {
114 let cell = Self::new();
115 if let Some(value) = self.try_get() {
116 match cell.set(value.clone()) {
117 Ok(()) => (),
118 Err(_) => unreachable!(),
119 }
120 }
121 cell
122 }
123}
124
125#[allow(dead_code)]
126impl<T> OnceLock<T> {
127 pub const fn new() -> Self {
128 OnceLock {
129 once: Once::new(),
130 value: UnsafeCell::new(MaybeUninit::uninit()),
131 _marker: PhantomData,
132 }
133 }
134
135 pub fn set(&self, value: T) -> Result<(), T> {
136 if self.is_completed() {
137 return Err(value);
138 }
139 self.init(|| Ok(value))
140 }
141
142 pub fn get(&self) -> &T {
143 if self.once.is_completed() {
144 unsafe { self.get_unchecked() }
145 } else {
146 panic!("OnceLock::get called before OnceLock::set");
147 }
148 }
149
150 pub fn try_get(&self) -> Option<&T> {
151 if self.once.is_completed() {
152 Some(unsafe { self.get_unchecked() })
153 } else {
154 None
155 }
156 }
157
158 pub fn get_or_init<F>(&self, f: F) -> &T
159 where
160 F: FnOnce() -> T,
161 {
162 match self.get_or_try_init(|| Ok::<T, ()>(f())) {
163 Ok(val) => val,
164 Err(_) => panic!(),
165 }
166 }
167
168 pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
169 where
170 F: FnOnce() -> Result<T, E>,
171 {
172 if let Some(value) = self.try_get() {
178 return Ok(value);
179 }
180 self.init(f)?;
181
182 debug_assert!(self.is_completed());
183
184 Ok(unsafe { self.get_unchecked() })
186 }
187
188 #[cold]
189 fn init<F, E>(&self, f: F) -> Result<(), E>
190 where
191 F: FnOnce() -> Result<T, E>,
192 {
193 let mut res: Result<(), E> = Ok(());
194 let slot = &self.value;
195
196 self.once.call(|| match f() {
199 Ok(value) => {
200 unsafe { (*slot.get()).write(value) };
201 }
202 Err(e) => {
203 res = Err(e);
204 }
205 });
206 res
207 }
208
209 unsafe fn get_unchecked(&self) -> &T {
210 debug_assert!(self.once.is_completed());
211 (*self.value.get()).assume_init_ref()
212 }
213
214 fn is_completed(&self) -> bool {
215 self.once.is_completed()
216 }
217}
218
219impl<T> Drop for OnceLock<T> {
220 fn drop(&mut self) {
221 if self.once.is_completed() {
222 unsafe {
223 (*self.value.get()).assume_init_drop();
224 }
225 }
226 }
227}