1 //! Thread-safe, non-blocking, "first one wins" flavor of `OnceCell`. 2 //! 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. 6 //! 7 //! This module does not require `std` feature. 8 9 #[cfg(feature = "atomic-polyfill")] 10 use atomic_polyfill as atomic; 11 #[cfg(not(feature = "atomic-polyfill"))] 12 use core::sync::atomic; 13 14 use atomic::{AtomicUsize, Ordering}; 15 use core::num::NonZeroUsize; 16 17 /// A thread-safe cell which can be written to only once. 18 #[derive(Default, Debug)] 19 pub struct OnceNonZeroUsize { 20 inner: AtomicUsize, 21 } 22 23 impl OnceNonZeroUsize { 24 /// Creates a new empty cell. 25 #[inline] new() -> OnceNonZeroUsize26 pub const fn new() -> OnceNonZeroUsize { 27 OnceNonZeroUsize { inner: AtomicUsize::new(0) } 28 } 29 30 /// Gets the underlying value. 31 #[inline] get(&self) -> Option<NonZeroUsize>32 pub fn get(&self) -> Option<NonZeroUsize> { 33 let val = self.inner.load(Ordering::Acquire); 34 NonZeroUsize::new(val) 35 } 36 37 /// Sets the contents of this cell to `value`. 38 /// 39 /// Returns `Ok(())` if the cell was empty and `Err(())` if it was 40 /// full. 41 #[inline] set(&self, value: NonZeroUsize) -> Result<(), ()>42 pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> { 43 let exchange = 44 self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire); 45 match exchange { 46 Ok(_) => Ok(()), 47 Err(_) => Err(()), 48 } 49 } 50 51 /// Gets the contents of the cell, initializing it with `f` if the cell was 52 /// empty. 53 /// 54 /// If several threads concurrently run `get_or_init`, more than one `f` can 55 /// be called. However, all threads will return the same value, produced by 56 /// some `f`. get_or_init<F>(&self, f: F) -> NonZeroUsize where F: FnOnce() -> NonZeroUsize,57 pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize 58 where 59 F: FnOnce() -> NonZeroUsize, 60 { 61 enum Void {} 62 match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) { 63 Ok(val) => val, 64 Err(void) => match void {}, 65 } 66 } 67 68 /// Gets the contents of the cell, initializing it with `f` if 69 /// the cell was empty. If the cell was empty and `f` failed, an 70 /// error is returned. 71 /// 72 /// If several threads concurrently run `get_or_init`, more than one `f` can 73 /// be called. However, all threads will return the same value, produced by 74 /// some `f`. get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E> where F: FnOnce() -> Result<NonZeroUsize, E>,75 pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E> 76 where 77 F: FnOnce() -> Result<NonZeroUsize, E>, 78 { 79 let val = self.inner.load(Ordering::Acquire); 80 let res = match NonZeroUsize::new(val) { 81 Some(it) => it, 82 None => { 83 let mut val = f()?.get(); 84 let exchange = 85 self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire); 86 if let Err(old) = exchange { 87 val = old; 88 } 89 unsafe { NonZeroUsize::new_unchecked(val) } 90 } 91 }; 92 Ok(res) 93 } 94 } 95 96 /// A thread-safe cell which can be written to only once. 97 #[derive(Default, Debug)] 98 pub struct OnceBool { 99 inner: OnceNonZeroUsize, 100 } 101 102 impl OnceBool { 103 /// Creates a new empty cell. 104 #[inline] new() -> OnceBool105 pub const fn new() -> OnceBool { 106 OnceBool { inner: OnceNonZeroUsize::new() } 107 } 108 109 /// Gets the underlying value. 110 #[inline] get(&self) -> Option<bool>111 pub fn get(&self) -> Option<bool> { 112 self.inner.get().map(OnceBool::from_usize) 113 } 114 115 /// Sets the contents of this cell to `value`. 116 /// 117 /// Returns `Ok(())` if the cell was empty and `Err(())` if it was 118 /// full. 119 #[inline] set(&self, value: bool) -> Result<(), ()>120 pub fn set(&self, value: bool) -> Result<(), ()> { 121 self.inner.set(OnceBool::to_usize(value)) 122 } 123 124 /// Gets the contents of the cell, initializing it with `f` if the cell was 125 /// empty. 126 /// 127 /// If several threads concurrently run `get_or_init`, more than one `f` can 128 /// be called. However, all threads will return the same value, produced by 129 /// some `f`. get_or_init<F>(&self, f: F) -> bool where F: FnOnce() -> bool,130 pub fn get_or_init<F>(&self, f: F) -> bool 131 where 132 F: FnOnce() -> bool, 133 { 134 OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f()))) 135 } 136 137 /// Gets the contents of the cell, initializing it with `f` if 138 /// the cell was empty. If the cell was empty and `f` failed, an 139 /// error is returned. 140 /// 141 /// If several threads concurrently run `get_or_init`, more than one `f` can 142 /// be called. However, all threads will return the same value, produced by 143 /// some `f`. get_or_try_init<F, E>(&self, f: F) -> Result<bool, E> where F: FnOnce() -> Result<bool, E>,144 pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E> 145 where 146 F: FnOnce() -> Result<bool, E>, 147 { 148 self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize) 149 } 150 151 #[inline] from_usize(value: NonZeroUsize) -> bool152 fn from_usize(value: NonZeroUsize) -> bool { 153 value.get() == 1 154 } 155 #[inline] to_usize(value: bool) -> NonZeroUsize156 fn to_usize(value: bool) -> NonZeroUsize { 157 unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) } 158 } 159 } 160 161 #[cfg(feature = "alloc")] 162 pub use self::once_box::OnceBox; 163 164 #[cfg(feature = "alloc")] 165 mod once_box { 166 use super::atomic::{AtomicPtr, Ordering}; 167 use core::{marker::PhantomData, ptr}; 168 169 use alloc::boxed::Box; 170 171 /// A thread-safe cell which can be written to only once. 172 pub struct OnceBox<T> { 173 inner: AtomicPtr<T>, 174 ghost: PhantomData<Option<Box<T>>>, 175 } 176 177 impl<T> core::fmt::Debug for OnceBox<T> { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result178 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 179 write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed)) 180 } 181 } 182 183 impl<T> Default for OnceBox<T> { default() -> Self184 fn default() -> Self { 185 Self::new() 186 } 187 } 188 189 impl<T> Drop for OnceBox<T> { drop(&mut self)190 fn drop(&mut self) { 191 let ptr = *self.inner.get_mut(); 192 if !ptr.is_null() { 193 drop(unsafe { Box::from_raw(ptr) }) 194 } 195 } 196 } 197 198 impl<T> OnceBox<T> { 199 /// Creates a new empty cell. new() -> OnceBox<T>200 pub const fn new() -> OnceBox<T> { 201 OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData } 202 } 203 204 /// Gets a reference to the underlying value. get(&self) -> Option<&T>205 pub fn get(&self) -> Option<&T> { 206 let ptr = self.inner.load(Ordering::Acquire); 207 if ptr.is_null() { 208 return None; 209 } 210 Some(unsafe { &*ptr }) 211 } 212 213 /// Sets the contents of this cell to `value`. 214 /// 215 /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was 216 /// full. set(&self, value: Box<T>) -> Result<(), Box<T>>217 pub fn set(&self, value: Box<T>) -> Result<(), Box<T>> { 218 let ptr = Box::into_raw(value); 219 let exchange = self.inner.compare_exchange( 220 ptr::null_mut(), 221 ptr, 222 Ordering::AcqRel, 223 Ordering::Acquire, 224 ); 225 if let Err(_) = exchange { 226 let value = unsafe { Box::from_raw(ptr) }; 227 return Err(value); 228 } 229 Ok(()) 230 } 231 232 /// Gets the contents of the cell, initializing it with `f` if the cell was 233 /// empty. 234 /// 235 /// If several threads concurrently run `get_or_init`, more than one `f` can 236 /// be called. However, all threads will return the same value, produced by 237 /// some `f`. get_or_init<F>(&self, f: F) -> &T where F: FnOnce() -> Box<T>,238 pub fn get_or_init<F>(&self, f: F) -> &T 239 where 240 F: FnOnce() -> Box<T>, 241 { 242 enum Void {} 243 match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) { 244 Ok(val) => val, 245 Err(void) => match void {}, 246 } 247 } 248 249 /// Gets the contents of the cell, initializing it with `f` if 250 /// the cell was empty. If the cell was empty and `f` failed, an 251 /// error is returned. 252 /// 253 /// If several threads concurrently run `get_or_init`, more than one `f` can 254 /// be called. However, all threads will return the same value, produced by 255 /// some `f`. get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result<Box<T>, E>,256 pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> 257 where 258 F: FnOnce() -> Result<Box<T>, E>, 259 { 260 let mut ptr = self.inner.load(Ordering::Acquire); 261 262 if ptr.is_null() { 263 let val = f()?; 264 ptr = Box::into_raw(val); 265 let exchange = self.inner.compare_exchange( 266 ptr::null_mut(), 267 ptr, 268 Ordering::AcqRel, 269 Ordering::Acquire, 270 ); 271 if let Err(old) = exchange { 272 drop(unsafe { Box::from_raw(ptr) }); 273 ptr = old; 274 } 275 }; 276 Ok(unsafe { &*ptr }) 277 } 278 } 279 280 unsafe impl<T: Sync + Send> Sync for OnceBox<T> {} 281 282 /// ```compile_fail 283 /// struct S(*mut ()); 284 /// unsafe impl Sync for S {} 285 /// 286 /// fn share<T: Sync>(_: &T) {} 287 /// share(&once_cell::race::OnceBox::<S>::new()); 288 /// ``` _dummy()289 fn _dummy() {} 290 } 291