Coverage Report

Created: 2025-02-26 06:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.20.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
#[cfg(not(feature = "portable-atomic"))]
23
use core::sync::atomic;
24
#[cfg(feature = "portable-atomic")]
25
use portable_atomic as atomic;
26
27
use atomic::{AtomicPtr, AtomicUsize, Ordering};
28
use core::cell::UnsafeCell;
29
use core::marker::PhantomData;
30
use core::num::NonZeroUsize;
31
use core::ptr;
32
33
/// A thread-safe cell which can be written to only once.
34
#[derive(Default, Debug)]
35
pub struct OnceNonZeroUsize {
36
    inner: AtomicUsize,
37
}
38
39
impl OnceNonZeroUsize {
40
    /// Creates a new empty cell.
41
    #[inline]
42
0
    pub const fn new() -> OnceNonZeroUsize {
43
0
        OnceNonZeroUsize { inner: AtomicUsize::new(0) }
44
0
    }
45
46
    /// Gets the underlying value.
47
    #[inline]
48
0
    pub fn get(&self) -> Option<NonZeroUsize> {
49
0
        let val = self.inner.load(Ordering::Acquire);
50
0
        NonZeroUsize::new(val)
51
0
    }
52
53
    /// Sets the contents of this cell to `value`.
54
    ///
55
    /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
56
    /// full.
57
    #[inline]
58
0
    pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> {
59
0
        let exchange =
60
0
            self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire);
61
0
        match exchange {
62
0
            Ok(_) => Ok(()),
63
0
            Err(_) => Err(()),
64
        }
65
0
    }
66
67
    /// Gets the contents of the cell, initializing it with `f` if the cell was
68
    /// empty.
69
    ///
70
    /// If several threads concurrently run `get_or_init`, more than one `f` can
71
    /// be called. However, all threads will return the same value, produced by
72
    /// some `f`.
73
0
    pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize
74
0
    where
75
0
        F: FnOnce() -> NonZeroUsize,
76
0
    {
77
        enum Void {}
78
0
        match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) {
79
0
            Ok(val) => val,
80
0
            Err(void) => match void {},
81
0
        }
82
0
    }
83
84
    /// Gets the contents of the cell, initializing it with `f` if
85
    /// the cell was empty. If the cell was empty and `f` failed, an
86
    /// error is returned.
87
    ///
88
    /// If several threads concurrently run `get_or_init`, more than one `f` can
89
    /// be called. However, all threads will return the same value, produced by
90
    /// some `f`.
91
0
    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E>
92
0
    where
93
0
        F: FnOnce() -> Result<NonZeroUsize, E>,
94
0
    {
95
0
        let val = self.inner.load(Ordering::Acquire);
96
0
        match NonZeroUsize::new(val) {
97
0
            Some(it) => Ok(it),
98
0
            None => self.init(f),
99
        }
100
0
    }
101
102
    #[cold]
103
    #[inline(never)]
104
0
    fn init<E>(&self, f: impl FnOnce() -> Result<NonZeroUsize, E>) -> Result<NonZeroUsize, E> {
105
0
        let mut val = f()?.get();
106
0
        let exchange = self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire);
107
0
        if let Err(old) = exchange {
108
0
            val = old;
109
0
        }
110
0
        Ok(unsafe { NonZeroUsize::new_unchecked(val) })
111
0
    }
112
}
113
114
/// A thread-safe cell which can be written to only once.
115
#[derive(Default, Debug)]
116
pub struct OnceBool {
117
    inner: OnceNonZeroUsize,
118
}
119
120
impl OnceBool {
121
    /// Creates a new empty cell.
122
    #[inline]
123
0
    pub const fn new() -> OnceBool {
124
0
        OnceBool { inner: OnceNonZeroUsize::new() }
125
0
    }
126
127
    /// Gets the underlying value.
128
    #[inline]
129
0
    pub fn get(&self) -> Option<bool> {
130
0
        self.inner.get().map(OnceBool::from_usize)
131
0
    }
132
133
    /// Sets the contents of this cell to `value`.
134
    ///
135
    /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
136
    /// full.
137
    #[inline]
138
0
    pub fn set(&self, value: bool) -> Result<(), ()> {
139
0
        self.inner.set(OnceBool::to_usize(value))
140
0
    }
141
142
    /// Gets the contents of the cell, initializing it with `f` if the cell was
143
    /// empty.
144
    ///
145
    /// If several threads concurrently run `get_or_init`, more than one `f` can
146
    /// be called. However, all threads will return the same value, produced by
147
    /// some `f`.
148
0
    pub fn get_or_init<F>(&self, f: F) -> bool
149
0
    where
150
0
        F: FnOnce() -> bool,
151
0
    {
152
0
        OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f())))
153
0
    }
154
155
    /// Gets the contents of the cell, initializing it with `f` if
156
    /// the cell was empty. If the cell was empty and `f` failed, an
157
    /// error is returned.
158
    ///
159
    /// If several threads concurrently run `get_or_init`, more than one `f` can
160
    /// be called. However, all threads will return the same value, produced by
161
    /// some `f`.
162
0
    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E>
163
0
    where
164
0
        F: FnOnce() -> Result<bool, E>,
165
0
    {
166
0
        self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize)
167
0
    }
168
169
    #[inline]
170
0
    fn from_usize(value: NonZeroUsize) -> bool {
171
0
        value.get() == 1
172
0
    }
173
174
    #[inline]
175
0
    fn to_usize(value: bool) -> NonZeroUsize {
176
0
        unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) }
177
0
    }
178
}
179
180
/// A thread-safe cell which can be written to only once.
181
pub struct OnceRef<'a, T> {
182
    inner: AtomicPtr<T>,
183
    ghost: PhantomData<UnsafeCell<&'a T>>,
184
}
185
186
// TODO: Replace UnsafeCell with SyncUnsafeCell once stabilized
187
unsafe impl<'a, T: Sync> Sync for OnceRef<'a, T> {}
188
189
impl<'a, T> core::fmt::Debug for OnceRef<'a, T> {
190
0
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
191
0
        write!(f, "OnceRef({:?})", self.inner)
192
0
    }
193
}
194
195
impl<'a, T> Default for OnceRef<'a, T> {
196
0
    fn default() -> Self {
197
0
        Self::new()
198
0
    }
199
}
200
201
impl<'a, T> OnceRef<'a, T> {
202
    /// Creates a new empty cell.
203
0
    pub const fn new() -> OnceRef<'a, T> {
204
0
        OnceRef { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
205
0
    }
206
207
    /// Gets a reference to the underlying value.
208
0
    pub fn get(&self) -> Option<&'a T> {
209
0
        let ptr = self.inner.load(Ordering::Acquire);
210
0
        unsafe { ptr.as_ref() }
211
0
    }
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.
217
0
    pub fn set(&self, value: &'a T) -> Result<(), ()> {
218
0
        let ptr = value as *const T as *mut T;
219
0
        let exchange =
220
0
            self.inner.compare_exchange(ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire);
221
0
        match exchange {
222
0
            Ok(_) => Ok(()),
223
0
            Err(_) => Err(()),
224
        }
225
0
    }
226
227
    /// Gets the contents of the cell, initializing it with `f` if the cell was
228
    /// empty.
229
    ///
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
232
    /// some `f`.
233
0
    pub fn get_or_init<F>(&self, f: F) -> &'a T
234
0
    where
235
0
        F: FnOnce() -> &'a T,
236
0
    {
237
        enum Void {}
238
0
        match self.get_or_try_init(|| Ok::<&'a T, Void>(f())) {
239
0
            Ok(val) => val,
240
0
            Err(void) => match void {},
241
0
        }
242
0
    }
243
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.
247
    ///
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
250
    /// some `f`.
251
0
    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&'a T, E>
252
0
    where
253
0
        F: FnOnce() -> Result<&'a T, E>,
254
0
    {
255
0
        let mut ptr = self.inner.load(Ordering::Acquire);
256
0
257
0
        if ptr.is_null() {
258
            // TODO replace with `cast_mut` when MSRV reaches 1.65.0 (also in `set`)
259
0
            ptr = f()? as *const T as *mut T;
260
0
            let exchange = self.inner.compare_exchange(
261
0
                ptr::null_mut(),
262
0
                ptr,
263
0
                Ordering::AcqRel,
264
0
                Ordering::Acquire,
265
0
            );
266
0
            if let Err(old) = exchange {
267
0
                ptr = old;
268
0
            }
269
0
        }
270
271
0
        Ok(unsafe { &*ptr })
272
0
    }
273
274
    /// ```compile_fail
275
    /// use once_cell::race::OnceRef;
276
    ///
277
    /// let mut l = OnceRef::new();
278
    ///
279
    /// {
280
    ///     let y = 2;
281
    ///     let mut r = OnceRef::new();
282
    ///     r.set(&y).unwrap();
283
    ///     core::mem::swap(&mut l, &mut r);
284
    /// }
285
    ///
286
    /// // l now contains a dangling reference to y
287
    /// eprintln!("uaf: {}", l.get().unwrap());
288
    /// ```
289
0
    fn _dummy() {}
290
}
291
292
#[cfg(feature = "alloc")]
293
pub use self::once_box::OnceBox;
294
295
#[cfg(feature = "alloc")]
296
mod once_box {
297
    use super::atomic::{AtomicPtr, Ordering};
298
    use core::{marker::PhantomData, ptr};
299
300
    use alloc::boxed::Box;
301
302
    /// A thread-safe cell which can be written to only once.
303
    pub struct OnceBox<T> {
304
        inner: AtomicPtr<T>,
305
        ghost: PhantomData<Option<Box<T>>>,
306
    }
307
308
    impl<T> core::fmt::Debug for OnceBox<T> {
309
0
        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
310
0
            write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed))
311
0
        }
312
    }
313
314
    impl<T> Default for OnceBox<T> {
315
0
        fn default() -> Self {
316
0
            Self::new()
317
0
        }
318
    }
319
320
    impl<T> Drop for OnceBox<T> {
321
0
        fn drop(&mut self) {
322
0
            let ptr = *self.inner.get_mut();
323
0
            if !ptr.is_null() {
324
0
                drop(unsafe { Box::from_raw(ptr) })
325
0
            }
326
0
        }
327
    }
328
329
    impl<T> OnceBox<T> {
330
        /// Creates a new empty cell.
331
0
        pub const fn new() -> OnceBox<T> {
332
0
            OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
333
0
        }
334
335
        /// Gets a reference to the underlying value.
336
0
        pub fn get(&self) -> Option<&T> {
337
0
            let ptr = self.inner.load(Ordering::Acquire);
338
0
            if ptr.is_null() {
339
0
                return None;
340
0
            }
341
0
            Some(unsafe { &*ptr })
342
0
        }
343
344
        /// Sets the contents of this cell to `value`.
345
        ///
346
        /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
347
        /// full.
348
0
        pub fn set(&self, value: Box<T>) -> Result<(), Box<T>> {
349
0
            let ptr = Box::into_raw(value);
350
0
            let exchange = self.inner.compare_exchange(
351
0
                ptr::null_mut(),
352
0
                ptr,
353
0
                Ordering::AcqRel,
354
0
                Ordering::Acquire,
355
0
            );
356
0
            if exchange.is_err() {
357
0
                let value = unsafe { Box::from_raw(ptr) };
358
0
                return Err(value);
359
0
            }
360
0
            Ok(())
361
0
        }
362
363
        /// Gets the contents of the cell, initializing it with `f` if the cell was
364
        /// empty.
365
        ///
366
        /// If several threads concurrently run `get_or_init`, more than one `f` can
367
        /// be called. However, all threads will return the same value, produced by
368
        /// some `f`.
369
0
        pub fn get_or_init<F>(&self, f: F) -> &T
370
0
        where
371
0
            F: FnOnce() -> Box<T>,
372
0
        {
373
            enum Void {}
374
0
            match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) {
375
0
                Ok(val) => val,
376
0
                Err(void) => match void {},
377
0
            }
378
0
        }
379
380
        /// Gets the contents of the cell, initializing it with `f` if
381
        /// the cell was empty. If the cell was empty and `f` failed, an
382
        /// error is returned.
383
        ///
384
        /// If several threads concurrently run `get_or_init`, more than one `f` can
385
        /// be called. However, all threads will return the same value, produced by
386
        /// some `f`.
387
0
        pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
388
0
        where
389
0
            F: FnOnce() -> Result<Box<T>, E>,
390
0
        {
391
0
            let mut ptr = self.inner.load(Ordering::Acquire);
392
0
393
0
            if ptr.is_null() {
394
0
                let val = f()?;
395
0
                ptr = Box::into_raw(val);
396
0
                let exchange = self.inner.compare_exchange(
397
0
                    ptr::null_mut(),
398
0
                    ptr,
399
0
                    Ordering::AcqRel,
400
0
                    Ordering::Acquire,
401
0
                );
402
0
                if let Err(old) = exchange {
403
0
                    drop(unsafe { Box::from_raw(ptr) });
404
0
                    ptr = old;
405
0
                }
406
0
            };
407
0
            Ok(unsafe { &*ptr })
408
0
        }
409
    }
410
411
    unsafe impl<T: Sync + Send> Sync for OnceBox<T> {}
412
413
    /// ```compile_fail
414
    /// struct S(*mut ());
415
    /// unsafe impl Sync for S {}
416
    ///
417
    /// fn share<T: Sync>(_: &T) {}
418
    /// share(&once_cell::race::OnceBox::<S>::new());
419
    /// ```
420
0
    fn _dummy() {}
421
}