Coverage Report

Created: 2026-04-09 06:25

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