Coverage Report

Created: 2025-11-24 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/once_cell-1.9.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
#[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]
26
0
    pub const fn new() -> OnceNonZeroUsize {
27
0
        OnceNonZeroUsize { inner: AtomicUsize::new(0) }
28
0
    }
29
30
    /// Gets the underlying value.
31
    #[inline]
32
0
    pub fn get(&self) -> Option<NonZeroUsize> {
33
0
        let val = self.inner.load(Ordering::Acquire);
34
0
        NonZeroUsize::new(val)
35
0
    }
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]
42
0
    pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> {
43
0
        let exchange =
44
0
            self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire);
45
0
        match exchange {
46
0
            Ok(_) => Ok(()),
47
0
            Err(_) => Err(()),
48
        }
49
0
    }
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`.
57
0
    pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize
58
0
    where
59
0
        F: FnOnce() -> NonZeroUsize,
60
0
    {
61
        enum Void {}
62
0
        match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) {
63
0
            Ok(val) => val,
64
0
            Err(void) => match void {},
65
0
        }
66
0
    }
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`.
75
0
    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E>
76
0
    where
77
0
        F: FnOnce() -> Result<NonZeroUsize, E>,
78
0
    {
79
0
        let val = self.inner.load(Ordering::Acquire);
80
0
        let res = match NonZeroUsize::new(val) {
81
0
            Some(it) => it,
82
            None => {
83
0
                let mut val = f()?.get();
84
0
                let exchange =
85
0
                    self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire);
86
0
                if let Err(old) = exchange {
87
0
                    val = old;
88
0
                }
89
0
                unsafe { NonZeroUsize::new_unchecked(val) }
90
            }
91
        };
92
0
        Ok(res)
93
0
    }
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]
105
0
    pub const fn new() -> OnceBool {
106
0
        OnceBool { inner: OnceNonZeroUsize::new() }
107
0
    }
108
109
    /// Gets the underlying value.
110
    #[inline]
111
0
    pub fn get(&self) -> Option<bool> {
112
0
        self.inner.get().map(OnceBool::from_usize)
113
0
    }
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]
120
0
    pub fn set(&self, value: bool) -> Result<(), ()> {
121
0
        self.inner.set(OnceBool::to_usize(value))
122
0
    }
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`.
130
0
    pub fn get_or_init<F>(&self, f: F) -> bool
131
0
    where
132
0
        F: FnOnce() -> bool,
133
0
    {
134
0
        OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f())))
135
0
    }
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`.
144
0
    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E>
145
0
    where
146
0
        F: FnOnce() -> Result<bool, E>,
147
0
    {
148
0
        self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize)
149
0
    }
150
151
    #[inline]
152
0
    fn from_usize(value: NonZeroUsize) -> bool {
153
0
        value.get() == 1
154
0
    }
155
    #[inline]
156
0
    fn to_usize(value: bool) -> NonZeroUsize {
157
0
        unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) }
158
0
    }
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> {
178
0
        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
179
0
            write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed))
180
0
        }
181
    }
182
183
    impl<T> Default for OnceBox<T> {
184
0
        fn default() -> Self {
185
0
            Self::new()
186
0
        }
187
    }
188
189
    impl<T> Drop for OnceBox<T> {
190
0
        fn drop(&mut self) {
191
0
            let ptr = *self.inner.get_mut();
192
0
            if !ptr.is_null() {
193
0
                drop(unsafe { Box::from_raw(ptr) })
194
0
            }
195
0
        }
196
    }
197
198
    impl<T> OnceBox<T> {
199
        /// Creates a new empty cell.
200
0
        pub const fn new() -> OnceBox<T> {
201
0
            OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
202
0
        }
203
204
        /// Gets a reference to the underlying value.
205
0
        pub fn get(&self) -> Option<&T> {
206
0
            let ptr = self.inner.load(Ordering::Acquire);
207
0
            if ptr.is_null() {
208
0
                return None;
209
0
            }
210
0
            Some(unsafe { &*ptr })
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: Box<T>) -> Result<(), Box<T>> {
218
0
            let ptr = Box::into_raw(value);
219
0
            let exchange = self.inner.compare_exchange(
220
0
                ptr::null_mut(),
221
0
                ptr,
222
0
                Ordering::AcqRel,
223
0
                Ordering::Acquire,
224
0
            );
225
0
            if let Err(_) = exchange {
226
0
                let value = unsafe { Box::from_raw(ptr) };
227
0
                return Err(value);
228
0
            }
229
0
            Ok(())
230
0
        }
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`.
238
0
        pub fn get_or_init<F>(&self, f: F) -> &T
239
0
        where
240
0
            F: FnOnce() -> Box<T>,
241
0
        {
242
            enum Void {}
243
0
            match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) {
244
0
                Ok(val) => val,
245
0
                Err(void) => match void {},
246
0
            }
247
0
        }
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`.
256
0
        pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
257
0
        where
258
0
            F: FnOnce() -> Result<Box<T>, E>,
259
0
        {
260
0
            let mut ptr = self.inner.load(Ordering::Acquire);
261
0
262
0
            if ptr.is_null() {
263
0
                let val = f()?;
264
0
                ptr = Box::into_raw(val);
265
0
                let exchange = self.inner.compare_exchange(
266
0
                    ptr::null_mut(),
267
0
                    ptr,
268
0
                    Ordering::AcqRel,
269
0
                    Ordering::Acquire,
270
0
                );
271
0
                if let Err(old) = exchange {
272
0
                    drop(unsafe { Box::from_raw(ptr) });
273
0
                    ptr = old;
274
0
                }
275
0
            };
276
0
            Ok(unsafe { &*ptr })
277
0
        }
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
    /// ```
289
0
    fn _dummy() {}
290
}