1use std::{
2 cell::UnsafeCell,
3 marker::PhantomData,
4 mem::MaybeUninit,
5 panic::{RefUnwindSafe, UnwindSafe},
6 sync::Once,
7};
8
9pub(crate) struct OnceLock<T> {
10 once: Once,
11 value: UnsafeCell<MaybeUninit<T>>,
12 _marker: PhantomData<T>,
13}
14
15impl<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
32unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
33unsafe impl<T: Send> Send for OnceLock<T> {}
34
35impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
36impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
37
38impl<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