/rust/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.21.3/src/race.rs
Line | Count | Source (jump to first uncovered line) |
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 | | //! # Atomic orderings |
10 | | //! |
11 | | //! All types in this module use `Acquire` and `Release` |
12 | | //! [atomic orderings](Ordering) for all their operations. While this is not |
13 | | //! strictly necessary for types other than `OnceBox`, it is useful for users as |
14 | | //! it allows them to be certain that after `get` or `get_or_init` returns on |
15 | | //! one thread, any side-effects caused by the setter thread prior to them |
16 | | //! calling `set` or `get_or_init` will be made visible to that thread; without |
17 | | //! it, it's possible for it to appear as if they haven't happened yet from the |
18 | | //! getter thread's perspective. This is an acceptable tradeoff to make since |
19 | | //! `Acquire` and `Release` have very little performance overhead on most |
20 | | //! architectures versus `Relaxed`. |
21 | | |
22 | | // The "atomic orderings" section of the documentation above promises |
23 | | // "happens-before" semantics. This drives the choice of orderings in the uses |
24 | | // of `compare_exchange` below. On success, the value was zero/null, so there |
25 | | // was nothing to acquire (there is never any `Ordering::Release` store of 0). |
26 | | // On failure, the value was nonzero, so it was initialized previously (perhaps |
27 | | // on another thread) using `Ordering::Release`, so we must use |
28 | | // `Ordering::Acquire` to ensure that store "happens-before" this load. |
29 | | |
30 | | #[cfg(not(feature = "portable-atomic"))] |
31 | | use core::sync::atomic; |
32 | | #[cfg(feature = "portable-atomic")] |
33 | | use portable_atomic as atomic; |
34 | | |
35 | | use atomic::{AtomicPtr, AtomicUsize, Ordering}; |
36 | | use core::cell::UnsafeCell; |
37 | | use core::marker::PhantomData; |
38 | | use core::num::NonZeroUsize; |
39 | | use core::ptr; |
40 | | |
41 | | /// A thread-safe cell which can be written to only once. |
42 | | #[derive(Default, Debug)] |
43 | | pub struct OnceNonZeroUsize { |
44 | | inner: AtomicUsize, |
45 | | } |
46 | | |
47 | | impl OnceNonZeroUsize { |
48 | | /// Creates a new empty cell. |
49 | | #[inline] |
50 | 0 | pub const fn new() -> Self { |
51 | 0 | Self { inner: AtomicUsize::new(0) } |
52 | 0 | } |
53 | | |
54 | | /// Gets the underlying value. |
55 | | #[inline] |
56 | 0 | pub fn get(&self) -> Option<NonZeroUsize> { |
57 | 0 | let val = self.inner.load(Ordering::Acquire); |
58 | 0 | NonZeroUsize::new(val) |
59 | 0 | } |
60 | | |
61 | | /// Get the reference to the underlying value, without checking if the cell |
62 | | /// is initialized. |
63 | | /// |
64 | | /// # Safety |
65 | | /// |
66 | | /// Caller must ensure that the cell is in initialized state, and that |
67 | | /// the contents are acquired by (synchronized to) this thread. |
68 | 0 | pub unsafe fn get_unchecked(&self) -> NonZeroUsize { |
69 | | #[inline(always)] |
70 | 0 | fn as_const_ptr(r: &AtomicUsize) -> *const usize { |
71 | | use core::mem::align_of; |
72 | | |
73 | 0 | let p: *const AtomicUsize = r; |
74 | | // SAFETY: "This type has the same size and bit validity as |
75 | | // the underlying integer type, usize. However, the alignment of |
76 | | // this type is always equal to its size, even on targets where |
77 | | // usize has a lesser alignment." |
78 | | const _ALIGNMENT_COMPATIBLE: () = |
79 | | assert!(align_of::<AtomicUsize>() % align_of::<usize>() == 0); |
80 | 0 | p.cast::<usize>() |
81 | 0 | } |
82 | | |
83 | | // TODO(MSRV-1.70): Use `AtomicUsize::as_ptr().cast_const()` |
84 | | // See https://github.com/rust-lang/rust/issues/138246. |
85 | 0 | let p = as_const_ptr(&self.inner); |
86 | 0 |
|
87 | 0 | // SAFETY: The caller is responsible for ensuring that the value |
88 | 0 | // was initialized and that the contents have been acquired by |
89 | 0 | // this thread. Assuming that, we can assume there will be no |
90 | 0 | // conflicting writes to the value since the value will never |
91 | 0 | // change once initialized. This relies on the statement in |
92 | 0 | // https://doc.rust-lang.org/1.83.0/core/sync/atomic/ that "(A |
93 | 0 | // `compare_exchange` or `compare_exchange_weak` that does not |
94 | 0 | // succeed is not considered a write." |
95 | 0 | let val = unsafe { p.read() }; |
96 | 0 |
|
97 | 0 | // SAFETY: The caller is responsible for ensuring the value is |
98 | 0 | // initialized and thus not zero. |
99 | 0 | unsafe { NonZeroUsize::new_unchecked(val) } |
100 | 0 | } |
101 | | |
102 | | /// Sets the contents of this cell to `value`. |
103 | | /// |
104 | | /// Returns `Ok(())` if the cell was empty and `Err(())` if it was |
105 | | /// full. |
106 | | #[inline] |
107 | 0 | pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> { |
108 | 0 | match self.compare_exchange(value) { |
109 | 0 | Ok(_) => Ok(()), |
110 | 0 | Err(_) => Err(()), |
111 | | } |
112 | 0 | } |
113 | | |
114 | | /// Gets the contents of the cell, initializing it with `f` if the cell was |
115 | | /// empty. |
116 | | /// |
117 | | /// If several threads concurrently run `get_or_init`, more than one `f` can |
118 | | /// be called. However, all threads will return the same value, produced by |
119 | | /// some `f`. |
120 | 0 | pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize |
121 | 0 | where |
122 | 0 | F: FnOnce() -> NonZeroUsize, |
123 | 0 | { |
124 | | enum Void {} |
125 | 0 | match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) { |
126 | 0 | Ok(val) => val, |
127 | 0 | Err(void) => match void {}, |
128 | 0 | } |
129 | 0 | } |
130 | | |
131 | | /// Gets the contents of the cell, initializing it with `f` if |
132 | | /// the cell was empty. If the cell was empty and `f` failed, an |
133 | | /// error is returned. |
134 | | /// |
135 | | /// If several threads concurrently run `get_or_init`, more than one `f` can |
136 | | /// be called. However, all threads will return the same value, produced by |
137 | | /// some `f`. |
138 | 0 | pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E> |
139 | 0 | where |
140 | 0 | F: FnOnce() -> Result<NonZeroUsize, E>, |
141 | 0 | { |
142 | 0 | match self.get() { |
143 | 0 | Some(it) => Ok(it), |
144 | 0 | None => self.init(f), |
145 | | } |
146 | 0 | } |
147 | | |
148 | | #[cold] |
149 | | #[inline(never)] |
150 | 0 | fn init<E>(&self, f: impl FnOnce() -> Result<NonZeroUsize, E>) -> Result<NonZeroUsize, E> { |
151 | 0 | let nz = f()?; |
152 | 0 | let mut val = nz.get(); |
153 | 0 | if let Err(old) = self.compare_exchange(nz) { |
154 | 0 | val = old; |
155 | 0 | } |
156 | 0 | Ok(unsafe { NonZeroUsize::new_unchecked(val) }) |
157 | 0 | } |
158 | | |
159 | | #[inline(always)] |
160 | 0 | fn compare_exchange(&self, val: NonZeroUsize) -> Result<usize, usize> { |
161 | 0 | self.inner.compare_exchange(0, val.get(), Ordering::Release, Ordering::Acquire) |
162 | 0 | } |
163 | | } |
164 | | |
165 | | /// A thread-safe cell which can be written to only once. |
166 | | #[derive(Default, Debug)] |
167 | | pub struct OnceBool { |
168 | | inner: OnceNonZeroUsize, |
169 | | } |
170 | | |
171 | | impl OnceBool { |
172 | | /// Creates a new empty cell. |
173 | | #[inline] |
174 | 0 | pub const fn new() -> Self { |
175 | 0 | Self { inner: OnceNonZeroUsize::new() } |
176 | 0 | } |
177 | | |
178 | | /// Gets the underlying value. |
179 | | #[inline] |
180 | 0 | pub fn get(&self) -> Option<bool> { |
181 | 0 | self.inner.get().map(Self::from_usize) |
182 | 0 | } |
183 | | |
184 | | /// Sets the contents of this cell to `value`. |
185 | | /// |
186 | | /// Returns `Ok(())` if the cell was empty and `Err(())` if it was |
187 | | /// full. |
188 | | #[inline] |
189 | 0 | pub fn set(&self, value: bool) -> Result<(), ()> { |
190 | 0 | self.inner.set(Self::to_usize(value)) |
191 | 0 | } |
192 | | |
193 | | /// Gets the contents of the cell, initializing it with `f` if the cell was |
194 | | /// empty. |
195 | | /// |
196 | | /// If several threads concurrently run `get_or_init`, more than one `f` can |
197 | | /// be called. However, all threads will return the same value, produced by |
198 | | /// some `f`. |
199 | 0 | pub fn get_or_init<F>(&self, f: F) -> bool |
200 | 0 | where |
201 | 0 | F: FnOnce() -> bool, |
202 | 0 | { |
203 | 0 | Self::from_usize(self.inner.get_or_init(|| Self::to_usize(f()))) |
204 | 0 | } |
205 | | |
206 | | /// Gets the contents of the cell, initializing it with `f` if |
207 | | /// the cell was empty. If the cell was empty and `f` failed, an |
208 | | /// error is returned. |
209 | | /// |
210 | | /// If several threads concurrently run `get_or_init`, more than one `f` can |
211 | | /// be called. However, all threads will return the same value, produced by |
212 | | /// some `f`. |
213 | 0 | pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E> |
214 | 0 | where |
215 | 0 | F: FnOnce() -> Result<bool, E>, |
216 | 0 | { |
217 | 0 | self.inner.get_or_try_init(|| f().map(Self::to_usize)).map(Self::from_usize) |
218 | 0 | } |
219 | | |
220 | | #[inline] |
221 | 0 | fn from_usize(value: NonZeroUsize) -> bool { |
222 | 0 | value.get() == 1 |
223 | 0 | } |
224 | | |
225 | | #[inline] |
226 | 0 | fn to_usize(value: bool) -> NonZeroUsize { |
227 | 0 | unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) } |
228 | 0 | } |
229 | | } |
230 | | |
231 | | /// A thread-safe cell which can be written to only once. |
232 | | pub struct OnceRef<'a, T> { |
233 | | inner: AtomicPtr<T>, |
234 | | ghost: PhantomData<UnsafeCell<&'a T>>, |
235 | | } |
236 | | |
237 | | // TODO: Replace UnsafeCell with SyncUnsafeCell once stabilized |
238 | | unsafe impl<'a, T: Sync> Sync for OnceRef<'a, T> {} |
239 | | |
240 | | impl<'a, T> core::fmt::Debug for OnceRef<'a, T> { |
241 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
242 | 0 | write!(f, "OnceRef({:?})", self.inner) |
243 | 0 | } |
244 | | } |
245 | | |
246 | | impl<'a, T> Default for OnceRef<'a, T> { |
247 | 0 | fn default() -> Self { |
248 | 0 | Self::new() |
249 | 0 | } |
250 | | } |
251 | | |
252 | | impl<'a, T> OnceRef<'a, T> { |
253 | | /// Creates a new empty cell. |
254 | 0 | pub const fn new() -> Self { |
255 | 0 | Self { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData } |
256 | 0 | } |
257 | | |
258 | | /// Gets a reference to the underlying value. |
259 | 0 | pub fn get(&self) -> Option<&'a T> { |
260 | 0 | let ptr = self.inner.load(Ordering::Acquire); |
261 | 0 | unsafe { ptr.as_ref() } |
262 | 0 | } |
263 | | |
264 | | /// Sets the contents of this cell to `value`. |
265 | | /// |
266 | | /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was |
267 | | /// full. |
268 | 0 | pub fn set(&self, value: &'a T) -> Result<(), ()> { |
269 | 0 | match self.compare_exchange(value) { |
270 | 0 | Ok(_) => Ok(()), |
271 | 0 | Err(_) => Err(()), |
272 | | } |
273 | 0 | } |
274 | | |
275 | | /// Gets the contents of the cell, initializing it with `f` if the cell was |
276 | | /// empty. |
277 | | /// |
278 | | /// If several threads concurrently run `get_or_init`, more than one `f` can |
279 | | /// be called. However, all threads will return the same value, produced by |
280 | | /// some `f`. |
281 | 0 | pub fn get_or_init<F>(&self, f: F) -> &'a T |
282 | 0 | where |
283 | 0 | F: FnOnce() -> &'a T, |
284 | 0 | { |
285 | | enum Void {} |
286 | 0 | match self.get_or_try_init(|| Ok::<&'a T, Void>(f())) { |
287 | 0 | Ok(val) => val, |
288 | 0 | Err(void) => match void {}, |
289 | 0 | } |
290 | 0 | } |
291 | | |
292 | | /// Gets the contents of the cell, initializing it with `f` if |
293 | | /// the cell was empty. If the cell was empty and `f` failed, an |
294 | | /// error is returned. |
295 | | /// |
296 | | /// If several threads concurrently run `get_or_init`, more than one `f` can |
297 | | /// be called. However, all threads will return the same value, produced by |
298 | | /// some `f`. |
299 | 0 | pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&'a T, E> |
300 | 0 | where |
301 | 0 | F: FnOnce() -> Result<&'a T, E>, |
302 | 0 | { |
303 | 0 | match self.get() { |
304 | 0 | Some(val) => Ok(val), |
305 | 0 | None => self.init(f), |
306 | | } |
307 | 0 | } |
308 | | |
309 | | #[cold] |
310 | | #[inline(never)] |
311 | 0 | fn init<E>(&self, f: impl FnOnce() -> Result<&'a T, E>) -> Result<&'a T, E> { |
312 | 0 | let mut value: &'a T = f()?; |
313 | 0 | if let Err(old) = self.compare_exchange(value) { |
314 | 0 | value = unsafe { &*old }; |
315 | 0 | } |
316 | 0 | Ok(value) |
317 | 0 | } |
318 | | |
319 | | #[inline(always)] |
320 | 0 | fn compare_exchange(&self, value: &'a T) -> Result<(), *const T> { |
321 | 0 | self.inner |
322 | 0 | .compare_exchange( |
323 | 0 | ptr::null_mut(), |
324 | 0 | <*const T>::cast_mut(value), |
325 | 0 | Ordering::Release, |
326 | 0 | Ordering::Acquire, |
327 | 0 | ) |
328 | 0 | .map(|_: *mut T| ()) |
329 | 0 | .map_err(<*mut T>::cast_const) |
330 | 0 | } |
331 | | |
332 | | /// ```compile_fail |
333 | | /// use once_cell::race::OnceRef; |
334 | | /// |
335 | | /// let mut l = OnceRef::new(); |
336 | | /// |
337 | | /// { |
338 | | /// let y = 2; |
339 | | /// let mut r = OnceRef::new(); |
340 | | /// r.set(&y).unwrap(); |
341 | | /// core::mem::swap(&mut l, &mut r); |
342 | | /// } |
343 | | /// |
344 | | /// // l now contains a dangling reference to y |
345 | | /// eprintln!("uaf: {}", l.get().unwrap()); |
346 | | /// ``` |
347 | 0 | fn _dummy() {} |
348 | | } |
349 | | |
350 | | #[cfg(feature = "alloc")] |
351 | | pub use self::once_box::OnceBox; |
352 | | |
353 | | #[cfg(feature = "alloc")] |
354 | | mod once_box { |
355 | | use super::atomic::{AtomicPtr, Ordering}; |
356 | | use core::{marker::PhantomData, ptr}; |
357 | | |
358 | | use alloc::boxed::Box; |
359 | | |
360 | | /// A thread-safe cell which can be written to only once. |
361 | | pub struct OnceBox<T> { |
362 | | inner: AtomicPtr<T>, |
363 | | ghost: PhantomData<Option<Box<T>>>, |
364 | | } |
365 | | |
366 | | impl<T> core::fmt::Debug for OnceBox<T> { |
367 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
368 | 0 | write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed)) |
369 | 0 | } |
370 | | } |
371 | | |
372 | | impl<T> Default for OnceBox<T> { |
373 | 0 | fn default() -> Self { |
374 | 0 | Self::new() |
375 | 0 | } |
376 | | } |
377 | | |
378 | | impl<T> Drop for OnceBox<T> { |
379 | 0 | fn drop(&mut self) { |
380 | 0 | let ptr = *self.inner.get_mut(); |
381 | 0 | if !ptr.is_null() { |
382 | 0 | drop(unsafe { Box::from_raw(ptr) }) |
383 | 0 | } |
384 | 0 | } Unexecuted instantiation: <once_cell::race::once_box::OnceBox<alloc::boxed::Box<dyn ahash::random_state::RandomSource + core::marker::Sync + core::marker::Send>> as core::ops::drop::Drop>::drop Unexecuted instantiation: <once_cell::race::once_box::OnceBox<_> as core::ops::drop::Drop>::drop |
385 | | } |
386 | | |
387 | | impl<T> OnceBox<T> { |
388 | | /// Creates a new empty cell. |
389 | 0 | pub const fn new() -> Self { |
390 | 0 | Self { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData } |
391 | 0 | } |
392 | | |
393 | | /// Creates a new cell with the given value. |
394 | 0 | pub fn with_value(value: Box<T>) -> Self { |
395 | 0 | Self { inner: AtomicPtr::new(Box::into_raw(value)), ghost: PhantomData } |
396 | 0 | } |
397 | | |
398 | | /// Gets a reference to the underlying value. |
399 | 1.21M | pub fn get(&self) -> Option<&T> { |
400 | 1.21M | let ptr = self.inner.load(Ordering::Acquire); |
401 | 1.21M | if ptr.is_null() { |
402 | 4 | return None; |
403 | 1.21M | } |
404 | 1.21M | Some(unsafe { &*ptr }) |
405 | 1.21M | } <once_cell::race::once_box::OnceBox<alloc::boxed::Box<dyn ahash::random_state::RandomSource + core::marker::Sync + core::marker::Send>>>::get Line | Count | Source | 399 | 1.21M | pub fn get(&self) -> Option<&T> { | 400 | 1.21M | let ptr = self.inner.load(Ordering::Acquire); | 401 | 1.21M | if ptr.is_null() { | 402 | 4 | return None; | 403 | 1.21M | } | 404 | 1.21M | Some(unsafe { &*ptr }) | 405 | 1.21M | } |
Unexecuted instantiation: <once_cell::race::once_box::OnceBox<_>>::get |
406 | | |
407 | | /// Sets the contents of this cell to `value`. |
408 | | /// |
409 | | /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was |
410 | | /// full. |
411 | 0 | pub fn set(&self, value: Box<T>) -> Result<(), Box<T>> { |
412 | 0 | let ptr = Box::into_raw(value); |
413 | 0 | let exchange = self.inner.compare_exchange( |
414 | 0 | ptr::null_mut(), |
415 | 0 | ptr, |
416 | 0 | Ordering::Release, |
417 | 0 | Ordering::Acquire, |
418 | 0 | ); |
419 | 0 | if exchange.is_err() { |
420 | 0 | let value = unsafe { Box::from_raw(ptr) }; |
421 | 0 | return Err(value); |
422 | 0 | } |
423 | 0 | Ok(()) |
424 | 0 | } |
425 | | |
426 | | /// Gets the contents of the cell, initializing it with `f` if the cell was |
427 | | /// empty. |
428 | | /// |
429 | | /// If several threads concurrently run `get_or_init`, more than one `f` can |
430 | | /// be called. However, all threads will return the same value, produced by |
431 | | /// some `f`. |
432 | 1.21M | pub fn get_or_init<F>(&self, f: F) -> &T |
433 | 1.21M | where |
434 | 1.21M | F: FnOnce() -> Box<T>, |
435 | 1.21M | { |
436 | | enum Void {} |
437 | 1.21M | match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) { <once_cell::race::once_box::OnceBox<alloc::boxed::Box<dyn ahash::random_state::RandomSource + core::marker::Sync + core::marker::Send>>>::get_or_init::<ahash::random_state::get_src::{closure#0}>::{closure#0} Line | Count | Source | 437 | 4 | match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) { |
Unexecuted instantiation: <once_cell::race::once_box::OnceBox<_>>::get_or_init::<_>::{closure#0} |
438 | 1.21M | Ok(val) => val, |
439 | 1.21M | Err(void) => match void {}, |
440 | 1.21M | } |
441 | 1.21M | } <once_cell::race::once_box::OnceBox<alloc::boxed::Box<dyn ahash::random_state::RandomSource + core::marker::Sync + core::marker::Send>>>::get_or_init::<ahash::random_state::get_src::{closure#0}> Line | Count | Source | 432 | 1.21M | pub fn get_or_init<F>(&self, f: F) -> &T | 433 | 1.21M | where | 434 | 1.21M | F: FnOnce() -> Box<T>, | 435 | 1.21M | { | 436 | | enum Void {} | 437 | 1.21M | match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) { | 438 | 1.21M | Ok(val) => val, | 439 | 1.21M | Err(void) => match void {}, | 440 | 1.21M | } | 441 | 1.21M | } |
Unexecuted instantiation: <once_cell::race::once_box::OnceBox<_>>::get_or_init::<_> |
442 | | |
443 | | /// Gets the contents of the cell, initializing it with `f` if |
444 | | /// the cell was empty. If the cell was empty and `f` failed, an |
445 | | /// error is returned. |
446 | | /// |
447 | | /// If several threads concurrently run `get_or_init`, more than one `f` can |
448 | | /// be called. However, all threads will return the same value, produced by |
449 | | /// some `f`. |
450 | 1.21M | pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> |
451 | 1.21M | where |
452 | 1.21M | F: FnOnce() -> Result<Box<T>, E>, |
453 | 1.21M | { |
454 | 1.21M | match self.get() { |
455 | 1.21M | Some(val) => Ok(val), |
456 | 4 | None => self.init(f) |
457 | | } |
458 | 1.21M | } <once_cell::race::once_box::OnceBox<alloc::boxed::Box<dyn ahash::random_state::RandomSource + core::marker::Sync + core::marker::Send>>>::get_or_try_init::<<once_cell::race::once_box::OnceBox<alloc::boxed::Box<dyn ahash::random_state::RandomSource + core::marker::Sync + core::marker::Send>>>::get_or_init<ahash::random_state::get_src::{closure#0}>::{closure#0}, <once_cell::race::once_box::OnceBox<_>>::get_or_init::Void> Line | Count | Source | 450 | 1.21M | pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> | 451 | 1.21M | where | 452 | 1.21M | F: FnOnce() -> Result<Box<T>, E>, | 453 | 1.21M | { | 454 | 1.21M | match self.get() { | 455 | 1.21M | Some(val) => Ok(val), | 456 | 4 | None => self.init(f) | 457 | | } | 458 | 1.21M | } |
Unexecuted instantiation: <once_cell::race::once_box::OnceBox<_>>::get_or_try_init::<_, _> |
459 | | |
460 | | #[cold] |
461 | | #[inline(never)] |
462 | 4 | fn init<E>(&self, f: impl FnOnce() -> Result<Box<T>, E>) -> Result<&T, E> { |
463 | 4 | let val = f()?; |
464 | 4 | let mut ptr = Box::into_raw(val); |
465 | 4 | let exchange = self.inner.compare_exchange( |
466 | 4 | ptr::null_mut(), |
467 | 4 | ptr, |
468 | 4 | Ordering::Release, |
469 | 4 | Ordering::Acquire, |
470 | 4 | ); |
471 | 4 | if let Err(old) = exchange { |
472 | 0 | drop(unsafe { Box::from_raw(ptr) }); |
473 | 0 | ptr = old; |
474 | 4 | } |
475 | 4 | Ok(unsafe { &*ptr }) |
476 | 4 | } <once_cell::race::once_box::OnceBox<alloc::boxed::Box<dyn ahash::random_state::RandomSource + core::marker::Sync + core::marker::Send>>>::init::<<once_cell::race::once_box::OnceBox<_>>::get_or_init::Void, <once_cell::race::once_box::OnceBox<alloc::boxed::Box<dyn ahash::random_state::RandomSource + core::marker::Sync + core::marker::Send>>>::get_or_init<ahash::random_state::get_src::{closure#0}>::{closure#0}> Line | Count | Source | 462 | 4 | fn init<E>(&self, f: impl FnOnce() -> Result<Box<T>, E>) -> Result<&T, E> { | 463 | 4 | let val = f()?; | 464 | 4 | let mut ptr = Box::into_raw(val); | 465 | 4 | let exchange = self.inner.compare_exchange( | 466 | 4 | ptr::null_mut(), | 467 | 4 | ptr, | 468 | 4 | Ordering::Release, | 469 | 4 | Ordering::Acquire, | 470 | 4 | ); | 471 | 4 | if let Err(old) = exchange { | 472 | 0 | drop(unsafe { Box::from_raw(ptr) }); | 473 | 0 | ptr = old; | 474 | 4 | } | 475 | 4 | Ok(unsafe { &*ptr }) | 476 | 4 | } |
Unexecuted instantiation: <once_cell::race::once_box::OnceBox<_>>::init::<_, _> |
477 | | } |
478 | | |
479 | | unsafe impl<T: Sync + Send> Sync for OnceBox<T> {} |
480 | | |
481 | | impl<T: Clone> Clone for OnceBox<T> { |
482 | 0 | fn clone(&self) -> Self { |
483 | 0 | match self.get() { |
484 | 0 | Some(value) => OnceBox::with_value(Box::new(value.clone())), |
485 | 0 | None => OnceBox::new(), |
486 | | } |
487 | 0 | } |
488 | | } |
489 | | |
490 | | /// ```compile_fail |
491 | | /// struct S(*mut ()); |
492 | | /// unsafe impl Sync for S {} |
493 | | /// |
494 | | /// fn share<T: Sync>(_: &T) {} |
495 | | /// share(&once_cell::race::OnceBox::<S>::new()); |
496 | | /// ``` |
497 | 0 | fn _dummy() {} |
498 | | } |