1 //! "First one wins" flavor of `OnceCell`.
3 //! If two threads race to initialize a type from the `race` module, they
4 //! don't block, execute initialization function together, but only one of
5 //! them stores the result.
7 //! This module does not require `std` feature.
11 sync
::atomic
::{AtomicUsize, Ordering}
,
14 /// A thread-safe cell which can be written to only once.
15 #[derive(Default, Debug)]
16 pub struct OnceNonZeroUsize
{
20 impl OnceNonZeroUsize
{
21 /// Creates a new empty cell.
23 pub const fn new() -> OnceNonZeroUsize
{
24 OnceNonZeroUsize { inner: AtomicUsize::new(0) }
27 /// Gets the underlying value.
29 pub fn get(&self) -> Option
<NonZeroUsize
> {
30 let val
= self.inner
.load(Ordering
::Acquire
);
31 NonZeroUsize
::new(val
)
34 /// Sets the contents of this cell to `value`.
36 /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
39 pub fn set(&self, value
: NonZeroUsize
) -> Result
<(), ()> {
41 self.inner
.compare_exchange(0, value
.get(), Ordering
::AcqRel
, Ordering
::Acquire
);
48 /// Gets the contents of the cell, initializing it with `f` if the cell was
51 /// If several threads concurrently run `get_or_init`, more than one `f` can
52 /// be called. However, all threads will return the same value, produced by
54 pub fn get_or_init
<F
>(&self, f
: F
) -> NonZeroUsize
56 F
: FnOnce() -> NonZeroUsize
,
59 match self.get_or_try_init(|| Ok
::<NonZeroUsize
, Void
>(f())) {
61 Err(void
) => match void {}
,
65 /// Gets the contents of the cell, initializing it with `f` if
66 /// the cell was empty. If the cell was empty and `f` failed, an
67 /// error is returned.
69 /// If several threads concurrently run `get_or_init`, more than one `f` can
70 /// be called. However, all threads will return the same value, produced by
72 pub fn get_or_try_init
<F
, E
>(&self, f
: F
) -> Result
<NonZeroUsize
, E
>
74 F
: FnOnce() -> Result
<NonZeroUsize
, E
>,
76 let val
= self.inner
.load(Ordering
::Acquire
);
77 let res
= match NonZeroUsize
::new(val
) {
80 let mut val
= f()?
.get();
82 self.inner
.compare_exchange(0, val
, Ordering
::AcqRel
, Ordering
::Acquire
);
83 if let Err(old
) = exchange
{
86 unsafe { NonZeroUsize::new_unchecked(val) }
93 /// A thread-safe cell which can be written to only once.
94 #[derive(Default, Debug)]
96 inner
: OnceNonZeroUsize
,
100 /// Creates a new empty cell.
102 pub const fn new() -> OnceBool
{
103 OnceBool { inner: OnceNonZeroUsize::new() }
106 /// Gets the underlying value.
108 pub fn get(&self) -> Option
<bool
> {
109 self.inner
.get().map(OnceBool
::from_usize
)
112 /// Sets the contents of this cell to `value`.
114 /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
117 pub fn set(&self, value
: bool
) -> Result
<(), ()> {
118 self.inner
.set(OnceBool
::to_usize(value
))
121 /// Gets the contents of the cell, initializing it with `f` if the cell was
124 /// If several threads concurrently run `get_or_init`, more than one `f` can
125 /// be called. However, all threads will return the same value, produced by
127 pub fn get_or_init
<F
>(&self, f
: F
) -> bool
131 OnceBool
::from_usize(self.inner
.get_or_init(|| OnceBool
::to_usize(f())))
134 /// Gets the contents of the cell, initializing it with `f` if
135 /// the cell was empty. If the cell was empty and `f` failed, an
136 /// error is returned.
138 /// If several threads concurrently run `get_or_init`, more than one `f` can
139 /// be called. However, all threads will return the same value, produced by
141 pub fn get_or_try_init
<F
, E
>(&self, f
: F
) -> Result
<bool
, E
>
143 F
: FnOnce() -> Result
<bool
, E
>,
145 self.inner
.get_or_try_init(|| f().map(OnceBool
::to_usize
)).map(OnceBool
::from_usize
)
149 fn from_usize(value
: NonZeroUsize
) -> bool
{
153 fn to_usize(value
: bool
) -> NonZeroUsize
{
154 unsafe { NonZeroUsize::new_unchecked(if value { 1 }
else { 2 }
) }
158 #[cfg(feature = "alloc")]
159 pub use self::once_box
::OnceBox
;
161 #[cfg(feature = "alloc")]
166 sync
::atomic
::{AtomicPtr, Ordering}
,
169 use alloc
::boxed
::Box
;
171 /// A thread-safe cell which can be written to only once.
173 pub struct OnceBox
<T
> {
175 ghost
: PhantomData
<Option
<Box
<T
>>>,
178 impl<T
> Default
for OnceBox
<T
> {
179 fn default() -> Self {
184 impl<T
> Drop
for OnceBox
<T
> {
186 let ptr
= *self.inner
.get_mut();
188 drop(unsafe { Box::from_raw(ptr) }
)
194 /// Creates a new empty cell.
195 pub const fn new() -> OnceBox
<T
> {
196 OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
199 /// Gets a reference to the underlying value.
200 pub fn get(&self) -> Option
<&T
> {
201 let ptr
= self.inner
.load(Ordering
::Acquire
);
205 Some(unsafe { &*ptr }
)
208 /// Sets the contents of this cell to `value`.
210 /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
212 pub fn set(&self, value
: Box
<T
>) -> Result
<(), Box
<T
>> {
213 let ptr
= Box
::into_raw(value
);
214 let exchange
= self.inner
.compare_exchange(
220 if let Err(_
) = exchange
{
221 let value
= unsafe { Box::from_raw(ptr) }
;
227 /// Gets the contents of the cell, initializing it with `f` if the cell was
230 /// If several threads concurrently run `get_or_init`, more than one `f` can
231 /// be called. However, all threads will return the same value, produced by
233 pub fn get_or_init
<F
>(&self, f
: F
) -> &T
235 F
: FnOnce() -> Box
<T
>,
238 match self.get_or_try_init(|| Ok
::<Box
<T
>, Void
>(f())) {
240 Err(void
) => match void {}
,
244 /// Gets the contents of the cell, initializing it with `f` if
245 /// the cell was empty. If the cell was empty and `f` failed, an
246 /// error is returned.
248 /// If several threads concurrently run `get_or_init`, more than one `f` can
249 /// be called. However, all threads will return the same value, produced by
251 pub fn get_or_try_init
<F
, E
>(&self, f
: F
) -> Result
<&T
, E
>
253 F
: FnOnce() -> Result
<Box
<T
>, E
>,
255 let mut ptr
= self.inner
.load(Ordering
::Acquire
);
259 ptr
= Box
::into_raw(val
);
260 let exchange
= self.inner
.compare_exchange(
266 if let Err(old
) = exchange
{
267 drop(unsafe { Box::from_raw(ptr) }
);
275 unsafe impl<T
: Sync
+ Send
> Sync
for OnceBox
<T
> {}
278 /// struct S(*mut ());
279 /// unsafe impl Sync for S {}
281 /// fn share<T: Sync>(_: &T) {}
282 /// share(&once_cell::race::OnceBox::<S>::new());