1 | use std::{ |
2 | cell::UnsafeCell, |
3 | marker::PhantomData, |
4 | mem::MaybeUninit, |
5 | panic::{RefUnwindSafe, UnwindSafe}, |
6 | sync::Once, |
7 | }; |
8 | |
9 | pub(crate) struct OnceLock<T> { |
10 | once: Once, |
11 | value: UnsafeCell<MaybeUninit<T>>, |
12 | _marker: PhantomData<T>, |
13 | } |
14 | |
15 | impl<T> OnceLock<T> { |
16 | pub(crate) const fn new() -> Self { |
17 | Self { |
18 | once: Once::new(), |
19 | value: UnsafeCell::new(MaybeUninit::uninit()), |
20 | _marker: PhantomData, |
21 | } |
22 | } |
23 | |
24 | pub(crate) fn get_or_init(&self, f: impl FnOnce() -> T) -> &T { |
25 | self.once.call_once(|| { |
26 | unsafe { &mut *self.value.get() }.write(val:f()); |
27 | }); |
28 | unsafe { (&*self.value.get()).assume_init_ref() } |
29 | } |
30 | } |
31 | |
32 | unsafe impl<T: Sync + Send> Sync for OnceLock<T> {} |
33 | unsafe impl<T: Send> Send for OnceLock<T> {} |
34 | |
35 | impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {} |
36 | impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {} |
37 | |
38 | impl<T> Drop for OnceLock<T> { |
39 | #[inline ] |
40 | fn drop(&mut self) { |
41 | if self.once.is_completed() { |
42 | // SAFETY: The cell is initialized and being dropped, so it can't |
43 | // be accessed again. |
44 | unsafe { self.value.get_mut().assume_init_drop() }; |
45 | } |
46 | } |
47 | } |
48 | |