4 panic
::{RefUnwindSafe, UnwindSafe}
,
5 sync
::atomic
::{AtomicBool, Ordering}
,
8 use parking_lot
::Mutex
;
10 pub(crate) struct OnceCell
<T
> {
12 is_initialized
: AtomicBool
,
13 value
: UnsafeCell
<Option
<T
>>,
16 // Why do we need `T: Send`?
17 // Thread A creates a `OnceCell` and shares it with
18 // scoped thread B, which fills the cell, which is
19 // then destroyed by A. That is, destructor observes
21 unsafe impl<T
: Sync
+ Send
> Sync
for OnceCell
<T
> {}
22 unsafe impl<T
: Send
> Send
for OnceCell
<T
> {}
24 impl<T
: RefUnwindSafe
+ UnwindSafe
> RefUnwindSafe
for OnceCell
<T
> {}
25 impl<T
: UnwindSafe
> UnwindSafe
for OnceCell
<T
> {}
28 pub(crate) const fn new() -> OnceCell
<T
> {
30 mutex
: parking_lot
::const_mutex(()),
31 is_initialized
: AtomicBool
::new(false),
32 value
: UnsafeCell
::new(None
),
36 /// Safety: synchronizes with store to value via Release/Acquire.
38 pub(crate) fn is_initialized(&self) -> bool
{
39 self.is_initialized
.load(Ordering
::Acquire
)
42 /// Safety: synchronizes with store to value via `is_initialized` or mutex
43 /// lock/unlock, writes value only once because of the mutex.
45 pub(crate) fn initialize
<F
, E
>(&self, f
: F
) -> Result
<(), E
>
47 F
: FnOnce() -> Result
<T
, E
>,
49 let _guard
= self.mutex
.lock();
50 if !self.is_initialized() {
51 // We are calling user-supplied function and need to be careful.
52 // - if it returns Err, we unlock mutex and return without touching anything
53 // - if it panics, we unlock mutex and propagate panic without touching anything
54 // - if it calls `set` or `get_or_try_init` re-entrantly, we get a deadlock on
55 // mutex, which is important for safety. We *could* detect this and panic,
56 // but that is more complicated
57 // - finally, if it returns Ok, we store the value and store the flag with
58 // `Release`, which synchronizes with `Acquire`s.
60 // Safe b/c we have a unique access and no panic may happen
61 // until the cell is marked as initialized.
62 let slot
: &mut Option
<T
> = unsafe { &mut *self.value.get() }
;
63 debug_assert
!(slot
.is_none());
65 self.is_initialized
.store(true, Ordering
::Release
);
70 /// Get the reference to the underlying value, without checking if the cell
75 /// Caller must ensure that the cell is in initialized state, and that
76 /// the contents are acquired by (synchronized to) this thread.
77 pub(crate) unsafe fn get_unchecked(&self) -> &T
{
78 debug_assert
!(self.is_initialized());
79 let slot
: &Option
<T
> = &*self.value
.get();
82 // This unsafe does improve performance, see `examples/bench`.
85 hint
::unreachable_unchecked()
90 /// Gets the mutable reference to the underlying value.
91 /// Returns `None` if the cell is empty.
92 pub(crate) fn get_mut(&mut self) -> Option
<&mut T
> {
93 // Safe b/c we have an exclusive access
94 let slot
: &mut Option
<T
> = unsafe { &mut *self.value.get() }
;
98 /// Consumes this `OnceCell`, returning the wrapped value.
99 /// Returns `None` if the cell was empty.
100 pub(crate) fn into_inner(self) -> Option
<T
> {
101 self.value
.into_inner()
107 use std
::mem
::size_of
;
109 assert_eq
!(size_of
::<OnceCell
<bool
>>(), 2 * size_of
::<bool
>() + size_of
::<u8>());