1 // Based on unstable std::sync::OnceLock.
2 //
3 // Source: https://github.com/rust-lang/rust/blob/8e9c93df464b7ada3fc7a1c8ccddd9dcb24ee0a0/library/std/src/sync/once_lock.rs
4 
5 use core::cell::UnsafeCell;
6 use core::mem::MaybeUninit;
7 use std::sync::Once;
8 
9 pub(crate) struct OnceLock<T> {
10     once: Once,
11     value: UnsafeCell<MaybeUninit<T>>,
12     // Unlike std::sync::OnceLock, we don't need PhantomData here because
13     // we don't use #[may_dangle].
14 }
15 
16 unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
17 unsafe impl<T: Send> Send for OnceLock<T> {}
18 
19 impl<T> OnceLock<T> {
20     /// Creates a new empty cell.
21     #[must_use]
new() -> Self22     pub(crate) const fn new() -> Self {
23         Self {
24             once: Once::new(),
25             value: UnsafeCell::new(MaybeUninit::uninit()),
26         }
27     }
28 
29     /// Gets the contents of the cell, initializing it with `f` if the cell
30     /// was empty.
31     ///
32     /// Many threads may call `get_or_init` concurrently with different
33     /// initializing functions, but it is guaranteed that only one function
34     /// will be executed.
35     ///
36     /// # Panics
37     ///
38     /// If `f` panics, the panic is propagated to the caller, and the cell
39     /// remains uninitialized.
40     ///
41     /// It is an error to reentrantly initialize the cell from `f`. The
42     /// exact outcome is unspecified. Current implementation deadlocks, but
43     /// this may be changed to a panic in the future.
get_or_init<F>(&self, f: F) -> &T where F: FnOnce() -> T,44     pub(crate) fn get_or_init<F>(&self, f: F) -> &T
45     where
46         F: FnOnce() -> T,
47     {
48         // Fast path check
49         if self.once.is_completed() {
50             // SAFETY: The inner value has been initialized
51             return unsafe { self.get_unchecked() };
52         }
53         self.initialize(f);
54 
55         // SAFETY: The inner value has been initialized
56         unsafe { self.get_unchecked() }
57     }
58 
59     #[cold]
initialize<F>(&self, f: F) where F: FnOnce() -> T,60     fn initialize<F>(&self, f: F)
61     where
62         F: FnOnce() -> T,
63     {
64         let slot = self.value.get();
65 
66         self.once.call_once(|| {
67             let value = f();
68             unsafe { slot.write(MaybeUninit::new(value)) }
69         });
70     }
71 
72     /// # Safety
73     ///
74     /// The value must be initialized
get_unchecked(&self) -> &T75     unsafe fn get_unchecked(&self) -> &T {
76         debug_assert!(self.once.is_completed());
77         &*self.value.get().cast::<T>()
78     }
79 }
80 
81 impl<T> Drop for OnceLock<T> {
drop(&mut self)82     fn drop(&mut self) {
83         if self.once.is_completed() {
84             // SAFETY: The inner value has been initialized
85             unsafe { (*self.value.get()).assume_init_drop() };
86         }
87     }
88 }
89