Coverage Report

Created: 2026-09-14 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/spin-0.9.9/src/once.rs
Line
Count
Source
1
//! Synchronization primitives for one-time evaluation.
2
3
use crate::{
4
    atomic::{AtomicU8, Ordering},
5
    RelaxStrategy, Spin,
6
};
7
use core::{
8
    cell::UnsafeCell,
9
    fmt,
10
    marker::PhantomData,
11
    mem::{ManuallyDrop, MaybeUninit},
12
};
13
14
/// A primitive that provides lazy one-time initialization.
15
///
16
/// Unlike its `std::sync` equivalent, this is generalized such that the closure returns a
17
/// value to be stored by the [`Once`] (`std::sync::Once` can be trivially emulated with
18
/// `Once`).
19
///
20
/// Because [`Once::new`] is `const`, this primitive may be used to safely initialize statics.
21
///
22
/// # Examples
23
///
24
/// ```
25
/// use spin;
26
///
27
/// static START: spin::Once = spin::Once::new();
28
///
29
/// START.call_once(|| {
30
///     // run initialization here
31
/// });
32
/// ```
33
pub struct Once<T = (), R = Spin> {
34
    phantom: PhantomData<R>,
35
    status: AtomicStatus,
36
    data: UnsafeCell<MaybeUninit<T>>,
37
}
38
39
impl<T, R> Default for Once<T, R> {
40
0
    fn default() -> Self {
41
0
        Self::new()
42
0
    }
43
}
44
45
impl<T: fmt::Debug, R> fmt::Debug for Once<T, R> {
46
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47
0
        match self.get() {
48
0
            Some(s) => write!(f, "Once {{ data: ")
49
0
                .and_then(|()| s.fmt(f))
50
0
                .and_then(|()| write!(f, "}}")),
51
0
            None => write!(f, "Once {{ <uninitialized> }}"),
52
        }
53
0
    }
54
}
55
56
// Same unsafe impls as `std::sync::RwLock`, because this also allows for
57
// concurrent reads.
58
unsafe impl<T: Send + Sync, R> Sync for Once<T, R> {}
59
unsafe impl<T: Send, R> Send for Once<T, R> {}
60
61
mod status {
62
    use super::*;
63
64
    // SAFETY: This structure has an invariant, namely that the inner atomic u8 must *always* have
65
    // a value for which there exists a valid Status. This means that users of this API must only
66
    // be allowed to load and store `Status`es.
67
    #[repr(transparent)]
68
    pub struct AtomicStatus(AtomicU8);
69
70
    // Four states that a Once can be in, encoded into the lower bits of `status` in
71
    // the Once structure.
72
    #[repr(u8)]
73
    #[derive(Clone, Copy, Debug, PartialEq)]
74
    pub enum Status {
75
        Incomplete = 0x00,
76
        Running = 0x01,
77
        Complete = 0x02,
78
        Panicked = 0x03,
79
    }
80
    impl Status {
81
        // Construct a status from an inner u8 integer.
82
        //
83
        // # Safety
84
        //
85
        // For this to be safe, the inner number must have a valid corresponding enum variant.
86
0
        unsafe fn new_unchecked(inner: u8) -> Self {
87
0
            core::mem::transmute(inner)
88
0
        }
89
    }
90
91
    impl AtomicStatus {
92
        #[inline(always)]
93
0
        pub const fn new(status: Status) -> Self {
94
            // SAFETY: We got the value directly from status, so transmuting back is fine.
95
0
            Self(AtomicU8::new(status as u8))
96
0
        }
97
        #[inline(always)]
98
0
        pub fn load(&self, ordering: Ordering) -> Status {
99
            // SAFETY: We know that the inner integer must have been constructed from a Status in
100
            // the first place.
101
0
            unsafe { Status::new_unchecked(self.0.load(ordering)) }
102
0
        }
103
        #[inline(always)]
104
0
        pub fn store(&self, status: Status, ordering: Ordering) {
105
            // SAFETY: While not directly unsafe, this is safe because the value was retrieved from
106
            // a status, thus making transmutation safe.
107
0
            self.0.store(status as u8, ordering);
108
0
        }
109
        #[inline(always)]
110
0
        pub fn compare_exchange(
111
0
            &self,
112
0
            old: Status,
113
0
            new: Status,
114
0
            success: Ordering,
115
0
            failure: Ordering,
116
0
        ) -> Result<Status, Status> {
117
0
            match self
118
0
                .0
119
0
                .compare_exchange(old as u8, new as u8, success, failure)
120
            {
121
                // SAFETY: A compare exchange will always return a value that was later stored into
122
                // the atomic u8, but due to the invariant that it must be a valid Status, we know
123
                // that both Ok(_) and Err(_) will be safely transmutable.
124
0
                Ok(ok) => Ok(unsafe { Status::new_unchecked(ok) }),
125
0
                Err(err) => Err(unsafe { Status::new_unchecked(err) }),
126
            }
127
0
        }
128
        #[inline(always)]
129
0
        pub fn get_mut(&mut self) -> &mut Status {
130
            // SAFETY: Since we know that the u8 inside must be a valid Status, we can safely cast
131
            // it to a &mut Status.
132
0
            unsafe { &mut *((self.0.get_mut() as *mut u8).cast::<Status>()) }
133
0
        }
134
    }
135
}
136
use self::status::{AtomicStatus, Status};
137
138
impl<T, R: RelaxStrategy> Once<T, R> {
139
    /// Performs an initialization routine once and only once. The given closure
140
    /// will be executed if this is the first time `call_once` has been called,
141
    /// and otherwise the routine will *not* be invoked.
142
    ///
143
    /// This method will block the calling thread if another initialization
144
    /// routine is currently running.
145
    ///
146
    /// When this function returns, it is guaranteed that some initialization
147
    /// has run and completed (it may not be the closure specified). The
148
    /// returned pointer will point to the result from the closure that was
149
    /// run.
150
    ///
151
    /// # Panics
152
    ///
153
    /// This function will panic if the [`Once`] previously panicked while attempting
154
    /// to initialize. This is similar to the poisoning behaviour of `std::sync`'s
155
    /// primitives.
156
    ///
157
    /// # Examples
158
    ///
159
    /// ```
160
    /// use spin;
161
    ///
162
    /// static INIT: spin::Once<usize> = spin::Once::new();
163
    ///
164
    /// fn get_cached_val() -> usize {
165
    ///     *INIT.call_once(expensive_computation)
166
    /// }
167
    ///
168
    /// fn expensive_computation() -> usize {
169
    ///     // ...
170
    /// # 2
171
    /// }
172
    /// ```
173
0
    pub fn call_once<F: FnOnce() -> T>(&self, f: F) -> &T {
174
0
        match self.try_call_once(|| Ok::<T, core::convert::Infallible>(f())) {
Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::call_once::<<flexi_logger::deferred_now::FORCE_UTC as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::call_once::<<flexi_logger::util::ERROR_CHANNEL as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::call_once::<<flexi_logger::formats::PALETTE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}
Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::call_once::<<spdmlib::crypto::spdm_ring::hash_impl::hash_ext::HASH_CTX_TABLE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}
Unexecuted instantiation: <spin::once::Once<_, _>>::call_once::<_>::{closure#0}
175
0
            Ok(x) => x,
176
            Err(void) => match void {},
177
        }
178
0
    }
Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::call_once::<<flexi_logger::deferred_now::FORCE_UTC as core::ops::deref::Deref>::deref::__static_ref_initialize>
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::call_once::<<flexi_logger::util::ERROR_CHANNEL as core::ops::deref::Deref>::deref::__static_ref_initialize>
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::call_once::<<flexi_logger::formats::PALETTE as core::ops::deref::Deref>::deref::__static_ref_initialize>
Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::call_once::<<spdmlib::crypto::spdm_ring::hash_impl::hash_ext::HASH_CTX_TABLE as core::ops::deref::Deref>::deref::__static_ref_initialize>
Unexecuted instantiation: <spin::once::Once<_, _>>::call_once::<_>
179
180
    /// This method is similar to `call_once`, but allows the given closure to
181
    /// fail, and lets the `Once` in a uninitialized state if it does.
182
    ///
183
    /// This method will block the calling thread if another initialization
184
    /// routine is currently running.
185
    ///
186
    /// When this function returns without error, it is guaranteed that some
187
    /// initialization has run and completed (it may not be the closure
188
    /// specified). The returned reference will point to the result from the
189
    /// closure that was run.
190
    ///
191
    /// # Panics
192
    ///
193
    /// This function will panic if the [`Once`] previously panicked while attempting
194
    /// to initialize. This is similar to the poisoning behaviour of `std::sync`'s
195
    /// primitives.
196
    ///
197
    /// # Examples
198
    ///
199
    /// ```
200
    /// use spin;
201
    ///
202
    /// static INIT: spin::Once<usize> = spin::Once::new();
203
    ///
204
    /// fn get_cached_val() -> Result<usize, String> {
205
    ///     INIT.try_call_once(expensive_fallible_computation).map(|x| *x)
206
    /// }
207
    ///
208
    /// fn expensive_fallible_computation() -> Result<usize, String> {
209
    ///     // ...
210
    /// # Ok(2)
211
    /// }
212
    /// ```
213
0
    pub fn try_call_once<F: FnOnce() -> Result<T, E>, E>(&self, f: F) -> Result<&T, E> {
214
0
        if let Some(value) = self.get() {
215
0
            Ok(value)
216
        } else {
217
0
            self.try_call_once_slow(f)
218
        }
219
0
    }
Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::try_call_once::<<spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::call_once<<flexi_logger::deferred_now::FORCE_UTC as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::try_call_once::<<spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::call_once<<flexi_logger::util::ERROR_CHANNEL as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::try_call_once::<<spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::call_once<<flexi_logger::formats::PALETTE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>
Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::try_call_once::<<spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::call_once<<spdmlib::crypto::spdm_ring::hash_impl::hash_ext::HASH_CTX_TABLE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>
Unexecuted instantiation: <spin::once::Once<_, _>>::try_call_once::<_, _>
220
221
    #[cold]
222
0
    fn try_call_once_slow<F: FnOnce() -> Result<T, E>, E>(&self, f: F) -> Result<&T, E> {
223
        loop {
224
0
            let xchg = self.status.compare_exchange(
225
0
                Status::Incomplete,
226
0
                Status::Running,
227
0
                Ordering::Acquire,
228
0
                Ordering::Acquire,
229
            );
230
231
0
            match xchg {
232
0
                Ok(_must_be_state_incomplete) => {
233
0
                    // Impl is defined after the match for readability
234
0
                }
235
0
                Err(Status::Panicked) => panic!("Once panicked"),
236
0
                Err(Status::Running) => match self.poll() {
237
0
                    Some(v) => return Ok(v),
238
0
                    None => continue,
239
                },
240
                Err(Status::Complete) => {
241
0
                    return Ok(unsafe {
242
0
                        // SAFETY: The status is Complete
243
0
                        self.force_get()
244
0
                    });
245
                }
246
                Err(Status::Incomplete) => {
247
                    // The compare_exchange failed, so this shouldn't ever be reached,
248
                    // however if we decide to switch to compare_exchange_weak it will
249
                    // be safer to leave this here than hit an unreachable
250
0
                    continue;
251
                }
252
            }
253
254
            // The compare-exchange succeeded, so we shall initialize it.
255
256
            // We use a guard (Finish) to catch panics caused by builder
257
0
            let finish = Finish {
258
0
                status: &self.status,
259
0
            };
260
0
            let val = match f() {
261
0
                Ok(val) => val,
262
0
                Err(err) => {
263
                    // If an error occurs, clean up everything and leave.
264
0
                    core::mem::forget(finish);
265
0
                    self.status.store(Status::Incomplete, Ordering::Release);
266
0
                    return Err(err);
267
                }
268
            };
269
0
            unsafe {
270
0
                // SAFETY:
271
0
                // `UnsafeCell`/deref: currently the only accessor, mutably
272
0
                // and immutably by cas exclusion.
273
0
                // `write`: pointer comes from `MaybeUninit`.
274
0
                (*self.data.get()).as_mut_ptr().write(val);
275
0
            };
276
            // If there were to be a panic with unwind enabled, the code would
277
            // short-circuit and never reach the point where it writes the inner data.
278
            // The destructor for Finish will run, and poison the Once to ensure that other
279
            // threads accessing it do not exhibit unwanted behavior, if there were to be
280
            // any inconsistency in data structures caused by the panicking thread.
281
            //
282
            // However, f() is expected in the general case not to panic. In that case, we
283
            // simply forget the guard, bypassing its destructor. We could theoretically
284
            // clear a flag instead, but this eliminates the call to the destructor at
285
            // compile time, and unconditionally poisons during an eventual panic, if
286
            // unwinding is enabled.
287
0
            core::mem::forget(finish);
288
289
            // SAFETY: Release is required here, so that all memory accesses done in the
290
            // closure when initializing, become visible to other threads that perform Acquire
291
            // loads.
292
            //
293
            // And, we also know that the changes this thread has done will not magically
294
            // disappear from our cache, so it does not need to be AcqRel.
295
0
            self.status.store(Status::Complete, Ordering::Release);
296
297
            // This next line is mainly an optimization.
298
0
            return unsafe { Ok(self.force_get()) };
299
        }
300
0
    }
Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::try_call_once_slow::<<spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::call_once<<flexi_logger::deferred_now::FORCE_UTC as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::try_call_once_slow::<<spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::call_once<<flexi_logger::util::ERROR_CHANNEL as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::try_call_once_slow::<<spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::call_once<<flexi_logger::formats::PALETTE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>
Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::try_call_once_slow::<<spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::call_once<<spdmlib::crypto::spdm_ring::hash_impl::hash_ext::HASH_CTX_TABLE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>
Unexecuted instantiation: <spin::once::Once<_, _>>::try_call_once_slow::<_, _>
301
302
    /// Spins until the [`Once`] contains a value.
303
    ///
304
    /// Note that in releases prior to `0.7`, this function had the behaviour of [`Once::poll`].
305
    ///
306
    /// # Panics
307
    ///
308
    /// This function will panic if the [`Once`] previously panicked while attempting
309
    /// to initialize. This is similar to the poisoning behaviour of `std::sync`'s
310
    /// primitives.
311
0
    pub fn wait(&self) -> &T {
312
        loop {
313
0
            match self.poll() {
314
0
                Some(x) => break x,
315
0
                None => R::relax(),
316
            }
317
        }
318
0
    }
319
320
    /// Like [`Once::get`], but will spin if the [`Once`] is in the process of being
321
    /// initialized. If initialization has not even begun, `None` will be returned.
322
    ///
323
    /// Note that in releases prior to `0.7`, this function was named `wait`.
324
    ///
325
    /// # Panics
326
    ///
327
    /// This function will panic if the [`Once`] previously panicked while attempting
328
    /// to initialize. This is similar to the poisoning behaviour of `std::sync`'s
329
    /// primitives.
330
0
    pub fn poll(&self) -> Option<&T> {
331
        loop {
332
            // SAFETY: Acquire is safe here, because if the status is COMPLETE, then we want to make
333
            // sure that all memory accessed done while initializing that value, are visible when
334
            // we return a reference to the inner data after this load.
335
0
            match self.status.load(Ordering::Acquire) {
336
0
                Status::Incomplete => return None,
337
0
                Status::Running => R::relax(), // We spin
338
0
                Status::Complete => return Some(unsafe { self.force_get() }),
339
0
                Status::Panicked => panic!("Once previously poisoned by a panicked"),
340
            }
341
        }
342
0
    }
Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::poll
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::poll
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::poll
Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::poll
Unexecuted instantiation: <spin::once::Once<_, _>>::poll
343
}
344
345
impl<T, R> Once<T, R> {
346
    /// Initialization constant of [`Once`].
347
    #[allow(clippy::declare_interior_mutable_const)]
348
    pub const INIT: Self = Self {
349
        phantom: PhantomData,
350
        status: AtomicStatus::new(Status::Incomplete),
351
        data: UnsafeCell::new(MaybeUninit::uninit()),
352
    };
353
354
    /// Creates a new [`Once`].
355
0
    pub const fn new() -> Self {
356
0
        Self::INIT
357
0
    }
358
359
    /// Creates a new initialized [`Once`].
360
0
    pub const fn initialized(data: T) -> Self {
361
0
        Self {
362
0
            phantom: PhantomData,
363
0
            status: AtomicStatus::new(Status::Complete),
364
0
            data: UnsafeCell::new(MaybeUninit::new(data)),
365
0
        }
366
0
    }
367
368
    /// Retrieve a pointer to the inner data.
369
    ///
370
    /// While this method itself is safe, accessing the pointer before the [`Once`] has been
371
    /// initialized is UB, unless this method has already been written to from a pointer coming
372
    /// from this method.
373
0
    pub fn as_mut_ptr(&self) -> *mut T {
374
        // SAFETY:
375
        // * MaybeUninit<T> always has exactly the same layout as T
376
0
        self.data.get().cast::<T>()
377
0
    }
378
379
    /// Get a reference to the initialized instance. Must only be called once COMPLETE.
380
0
    unsafe fn force_get(&self) -> &T {
381
        // SAFETY:
382
        // * `UnsafeCell`/inner deref: data never changes again
383
        // * `MaybeUninit`/outer deref: data was initialized
384
0
        &*(*self.data.get()).as_ptr()
385
0
    }
Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::force_get
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::force_get
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::force_get
Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::force_get
Unexecuted instantiation: <spin::once::Once<_, _>>::force_get
386
387
    /// Get a reference to the initialized instance. Must only be called once COMPLETE.
388
0
    unsafe fn force_get_mut(&mut self) -> &mut T {
389
        // SAFETY:
390
        // * `UnsafeCell`/inner deref: data never changes again
391
        // * `MaybeUninit`/outer deref: data was initialized
392
0
        &mut *(*self.data.get()).as_mut_ptr()
393
0
    }
394
395
    /// Get a reference to the initialized instance. Must only be called once COMPLETE.
396
0
    unsafe fn force_into_inner(self) -> T {
397
0
        let mut this = ManuallyDrop::new(self);
398
        // SAFETY:
399
        // * `UnsafeCell`/inner deref: data never changes again
400
        // * `MaybeUninit`/outer deref: data was initialized
401
        // * We never call `self`'s destructor, ensuring a double-drop cannot occur.
402
0
        this.data.get_mut().assume_init_read()
403
0
    }
404
405
    /// Returns a reference to the inner value if the [`Once`] has been initialized.
406
0
    pub fn get(&self) -> Option<&T> {
407
        // SAFETY: Just as with `poll`, Acquire is safe here because we want to be able to see the
408
        // nonatomic stores done when initializing, once we have loaded and checked the status.
409
0
        match self.status.load(Ordering::Acquire) {
410
0
            Status::Complete => Some(unsafe { self.force_get() }),
411
0
            _ => None,
412
        }
413
0
    }
Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::get
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::get
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::get
Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::get
Unexecuted instantiation: <spin::once::Once<_, _>>::get
414
415
    /// Returns a reference to the inner value on the unchecked assumption that the  [`Once`] has been initialized.
416
    ///
417
    /// # Safety
418
    ///
419
    /// This is *extremely* unsafe if the `Once` has not already been initialized because a reference to uninitialized
420
    /// memory will be returned, immediately triggering undefined behaviour (even if the reference goes unused).
421
    /// However, this can be useful in some instances for exposing the `Once` to FFI or when the overhead of atomically
422
    /// checking initialization is unacceptable and the `Once` has already been initialized.
423
0
    pub unsafe fn get_unchecked(&self) -> &T {
424
0
        debug_assert_eq!(
425
0
            self.status.load(Ordering::SeqCst),
426
            Status::Complete,
427
0
            "Attempted to access an uninitialized Once. If this was run without debug checks, this would be undefined behaviour. This is a serious bug and you must fix it.",
428
        );
429
0
        self.force_get()
430
0
    }
431
432
    /// Returns a mutable reference to the inner value if the [`Once`] has been initialized.
433
    ///
434
    /// Because this method requires a mutable reference to the [`Once`], no synchronization
435
    /// overhead is required to access the inner value. In effect, it is zero-cost.
436
0
    pub fn get_mut(&mut self) -> Option<&mut T> {
437
0
        match *self.status.get_mut() {
438
0
            Status::Complete => Some(unsafe { self.force_get_mut() }),
439
0
            _ => None,
440
        }
441
0
    }
442
443
    /// Returns a mutable reference to the inner value
444
    ///
445
    /// # Safety
446
    ///
447
    /// This is *extremely* unsafe if the `Once` has not already been initialized because a reference to uninitialized
448
    /// memory will be returned, immediately triggering undefined behaviour (even if the reference goes unused).
449
    /// However, this can be useful in some instances for exposing the `Once` to FFI or when the overhead of atomically
450
    /// checking initialization is unacceptable and the `Once` has already been initialized.
451
0
    pub unsafe fn get_mut_unchecked(&mut self) -> &mut T {
452
0
        debug_assert_eq!(
453
0
            self.status.load(Ordering::SeqCst),
454
            Status::Complete,
455
0
            "Attempted to access an unintialized Once.  If this was to run without debug checks, this would be undefined behavior.  This is a serious bug and you must fix it.",
456
        );
457
0
        self.force_get_mut()
458
0
    }
459
460
    /// Returns a the inner value if the [`Once`] has been initialized.
461
    ///
462
    /// Because this method requires ownership of the [`Once`], no synchronization overhead
463
    /// is required to access the inner value. In effect, it is zero-cost.
464
0
    pub fn try_into_inner(mut self) -> Option<T> {
465
0
        match *self.status.get_mut() {
466
0
            Status::Complete => Some(unsafe { self.force_into_inner() }),
467
0
            _ => None,
468
        }
469
0
    }
470
471
    /// Returns a the inner value if the [`Once`] has been initialized.  
472
    /// # Safety
473
    ///
474
    /// This is *extremely* unsafe if the `Once` has not already been initialized because a reference to uninitialized
475
    /// memory will be returned, immediately triggering undefined behaviour (even if the reference goes unused)
476
    /// This can be useful, if `Once` has already been initialized, and you want to bypass an
477
    /// option check.
478
0
    pub unsafe fn into_inner_unchecked(self) -> T {
479
0
        debug_assert_eq!(
480
0
            self.status.load(Ordering::SeqCst),
481
            Status::Complete,
482
0
            "Attempted to access an unintialized Once.  If this was to run without debug checks, this would be undefined behavior.  This is a serious bug and you must fix it.",
483
        );
484
0
        self.force_into_inner()
485
0
    }
486
487
    /// Checks whether the value has been initialized.
488
    ///
489
    /// This is done using [`Acquire`](core::sync::atomic::Ordering::Acquire) ordering, and
490
    /// therefore it is safe to access the value directly via
491
    /// [`get_unchecked`](Self::get_unchecked) if this returns true.
492
0
    pub fn is_completed(&self) -> bool {
493
        // TODO: Add a similar variant for Relaxed?
494
0
        self.status.load(Ordering::Acquire) == Status::Complete
495
0
    }
496
}
497
498
impl<T, R> From<T> for Once<T, R> {
499
0
    fn from(data: T) -> Self {
500
0
        Self::initialized(data)
501
0
    }
502
}
503
504
impl<T, R> Drop for Once<T, R> {
505
0
    fn drop(&mut self) {
506
        // No need to do any atomic access here, we have &mut!
507
0
        if *self.status.get_mut() == Status::Complete {
508
0
            unsafe {
509
0
                //TODO: Use MaybeUninit::assume_init_drop once stabilised
510
0
                core::ptr::drop_in_place((*self.data.get()).as_mut_ptr());
511
0
            }
512
0
        }
513
0
    }
Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::once::Once<_, _> as core::ops::drop::Drop>::drop
514
}
515
516
struct Finish<'a> {
517
    status: &'a AtomicStatus,
518
}
519
520
impl<'a> Drop for Finish<'a> {
521
0
    fn drop(&mut self) {
522
        // While using Relaxed here would most likely not be an issue, we use SeqCst anyway.
523
        // This is mainly because panics are not meant to be fast at all, but also because if
524
        // there were to be a compiler bug which reorders accesses within the same thread,
525
        // where it should not, we want to be sure that the panic really is handled, and does
526
        // not cause additional problems. SeqCst will therefore help guarding against such
527
        // bugs.
528
0
        self.status.store(Status::Panicked, Ordering::SeqCst);
529
0
    }
530
}
531
532
#[cfg(test)]
533
mod tests {
534
    use std::prelude::v1::*;
535
536
    use std::sync::atomic::AtomicU32;
537
    use std::sync::mpsc::channel;
538
    use std::sync::Arc;
539
    use std::thread;
540
541
    use super::*;
542
543
    #[test]
544
    fn smoke_once() {
545
        static O: Once = Once::new();
546
        let mut a = 0;
547
        O.call_once(|| a += 1);
548
        assert_eq!(a, 1);
549
        O.call_once(|| a += 1);
550
        assert_eq!(a, 1);
551
    }
552
553
    #[test]
554
    fn smoke_once_value() {
555
        static O: Once<usize> = Once::new();
556
        let a = O.call_once(|| 1);
557
        assert_eq!(*a, 1);
558
        let b = O.call_once(|| 2);
559
        assert_eq!(*b, 1);
560
    }
561
562
    #[test]
563
    fn stampede_once() {
564
        static O: Once = Once::new();
565
        static mut RUN: bool = false;
566
567
        let (tx, rx) = channel();
568
        let mut ts = Vec::new();
569
        for _ in 0..10 {
570
            let tx = tx.clone();
571
            ts.push(thread::spawn(move || {
572
                for _ in 0..4 {
573
                    thread::yield_now()
574
                }
575
                unsafe {
576
                    O.call_once(|| {
577
                        assert!(!RUN);
578
                        RUN = true;
579
                    });
580
                    assert!(RUN);
581
                }
582
                tx.send(()).unwrap();
583
            }));
584
        }
585
586
        unsafe {
587
            O.call_once(|| {
588
                assert!(!RUN);
589
                RUN = true;
590
            });
591
            assert!(RUN);
592
        }
593
594
        for _ in 0..10 {
595
            rx.recv().unwrap();
596
        }
597
598
        for t in ts {
599
            t.join().unwrap();
600
        }
601
    }
602
603
    #[test]
604
    fn get() {
605
        static INIT: Once<usize> = Once::new();
606
607
        assert!(INIT.get().is_none());
608
        INIT.call_once(|| 2);
609
        assert_eq!(INIT.get().map(|r| *r), Some(2));
610
    }
611
612
    #[test]
613
    fn get_no_wait() {
614
        static INIT: Once<usize> = Once::new();
615
616
        assert!(INIT.get().is_none());
617
        let t = thread::spawn(move || {
618
            INIT.call_once(|| {
619
                thread::sleep(std::time::Duration::from_secs(3));
620
                42
621
            });
622
        });
623
        assert!(INIT.get().is_none());
624
625
        t.join().unwrap();
626
    }
627
628
    #[test]
629
    fn poll() {
630
        static INIT: Once<usize> = Once::new();
631
632
        assert!(INIT.poll().is_none());
633
        INIT.call_once(|| 3);
634
        assert_eq!(INIT.poll().map(|r| *r), Some(3));
635
    }
636
637
    #[test]
638
    fn wait() {
639
        static INIT: Once<usize> = Once::new();
640
641
        let t = std::thread::spawn(|| {
642
            assert_eq!(*INIT.wait(), 3);
643
            assert!(INIT.is_completed());
644
        });
645
646
        for _ in 0..4 {
647
            thread::yield_now()
648
        }
649
650
        assert!(INIT.poll().is_none());
651
        INIT.call_once(|| 3);
652
653
        t.join().unwrap();
654
    }
655
656
    #[test]
657
    fn panic() {
658
        use std::panic;
659
660
        static INIT: Once = Once::new();
661
662
        // poison the once
663
        let t = panic::catch_unwind(|| {
664
            INIT.call_once(|| panic!());
665
        });
666
        assert!(t.is_err());
667
668
        // poisoning propagates
669
        let t = panic::catch_unwind(|| {
670
            INIT.call_once(|| {});
671
        });
672
        assert!(t.is_err());
673
    }
674
675
    #[test]
676
    fn init_constant() {
677
        static O: Once = Once::INIT;
678
        let mut a = 0;
679
        O.call_once(|| a += 1);
680
        assert_eq!(a, 1);
681
        O.call_once(|| a += 1);
682
        assert_eq!(a, 1);
683
    }
684
685
    static mut CALLED: bool = false;
686
687
    struct DropTest {}
688
689
    impl Drop for DropTest {
690
        fn drop(&mut self) {
691
            unsafe {
692
                CALLED = true;
693
            }
694
        }
695
    }
696
697
    #[test]
698
    fn try_call_once_err() {
699
        let once = Once::<_, Spin>::new();
700
        let shared = Arc::new((once, AtomicU32::new(0)));
701
702
        let (tx, rx) = channel();
703
704
        let t0 = {
705
            let shared = shared.clone();
706
            thread::spawn(move || {
707
                let (once, called) = &*shared;
708
709
                once.try_call_once(|| {
710
                    called.fetch_add(1, Ordering::AcqRel);
711
                    tx.send(()).unwrap();
712
                    thread::sleep(std::time::Duration::from_millis(50));
713
                    Err(())
714
                })
715
                .ok();
716
            })
717
        };
718
719
        let t1 = {
720
            let shared = shared.clone();
721
            thread::spawn(move || {
722
                rx.recv().unwrap();
723
                let (once, called) = &*shared;
724
                assert_eq!(
725
                    called.load(Ordering::Acquire),
726
                    1,
727
                    "leader thread did not run first"
728
                );
729
730
                once.call_once(|| {
731
                    called.fetch_add(1, Ordering::AcqRel);
732
                });
733
            })
734
        };
735
736
        t0.join().unwrap();
737
        t1.join().unwrap();
738
739
        assert_eq!(shared.1.load(Ordering::Acquire), 2);
740
    }
741
742
    // This is sort of two test cases, but if we write them as separate test methods
743
    // they can be executed concurrently and then fail some small fraction of the
744
    // time.
745
    #[test]
746
    fn drop_occurs_and_skip_uninit_drop() {
747
        unsafe {
748
            CALLED = false;
749
        }
750
751
        {
752
            let once = Once::<_>::new();
753
            once.call_once(|| DropTest {});
754
        }
755
756
        assert!(unsafe { CALLED });
757
        // Now test that we skip drops for the uninitialized case.
758
        unsafe {
759
            CALLED = false;
760
        }
761
762
        let once = Once::<DropTest>::new();
763
        drop(once);
764
765
        assert!(unsafe { !CALLED });
766
    }
767
768
    #[test]
769
    fn call_once_test() {
770
        for _ in 0..20 {
771
            use std::sync::atomic::AtomicUsize;
772
            use std::sync::Arc;
773
            use std::time::Duration;
774
            let share = Arc::new(AtomicUsize::new(0));
775
            let once = Arc::new(Once::<_, Spin>::new());
776
            let mut hs = Vec::new();
777
            for _ in 0..8 {
778
                let h = thread::spawn({
779
                    let share = share.clone();
780
                    let once = once.clone();
781
                    move || {
782
                        thread::sleep(Duration::from_millis(10));
783
                        once.call_once(|| {
784
                            share.fetch_add(1, Ordering::SeqCst);
785
                        });
786
                    }
787
                });
788
                hs.push(h);
789
            }
790
            for h in hs {
791
                h.join().unwrap();
792
            }
793
            assert_eq!(1, share.load(Ordering::SeqCst));
794
        }
795
    }
796
797
    #[test]
798
    fn init_from_ref_basic() {
799
        let once = Once::<usize, Spin>::new();
800
801
        let first = 1usize;
802
        let second = 2usize;
803
        assert_eq!(*once.init_from_ref(&first), 1);
804
        assert_eq!(*once.init_from_ref(&second), 1);
805
    }
806
807
    #[test]
808
    fn drop_boxed() {
809
        let boxed = Box::new(5);
810
        let once = Once::<_, Spin>::initialized(boxed);
811
        let boxed = once.try_into_inner().unwrap();
812
        println!("{}", boxed);
813
    }
814
}