1*863a3cffSLoGin use core::{ 2*863a3cffSLoGin fmt::{self, Debug, Formatter}, 3*863a3cffSLoGin sync::atomic::Ordering, 4*863a3cffSLoGin }; 5*863a3cffSLoGin 6*863a3cffSLoGin use atomic_enum::atomic_enum; 7*863a3cffSLoGin 8*863a3cffSLoGin pub struct Once { 9*863a3cffSLoGin inner: AtomicOnceState, 10*863a3cffSLoGin } 11*863a3cffSLoGin 12*863a3cffSLoGin #[atomic_enum] 13*863a3cffSLoGin #[derive(PartialEq, Eq)] 14*863a3cffSLoGin pub enum OnceState { 15*863a3cffSLoGin Incomplete, 16*863a3cffSLoGin Posioned, 17*863a3cffSLoGin Complete, 18*863a3cffSLoGin } 19*863a3cffSLoGin 20*863a3cffSLoGin #[allow(dead_code)] 21*863a3cffSLoGin impl Once { new() -> Self22*863a3cffSLoGin pub const fn new() -> Self { 23*863a3cffSLoGin Self { 24*863a3cffSLoGin inner: AtomicOnceState::new(OnceState::Incomplete), 25*863a3cffSLoGin } 26*863a3cffSLoGin } 27*863a3cffSLoGin 28*863a3cffSLoGin #[track_caller] call_once<F: FnOnce()>(&self, f: F)29*863a3cffSLoGin pub fn call_once<F: FnOnce()>(&self, f: F) { 30*863a3cffSLoGin if self.is_completed() { 31*863a3cffSLoGin return; 32*863a3cffSLoGin } 33*863a3cffSLoGin 34*863a3cffSLoGin // set initialized 35*863a3cffSLoGin let r = self.inner.compare_exchange( 36*863a3cffSLoGin OnceState::Incomplete, 37*863a3cffSLoGin OnceState::Posioned, 38*863a3cffSLoGin Ordering::SeqCst, 39*863a3cffSLoGin Ordering::SeqCst, 40*863a3cffSLoGin ); 41*863a3cffSLoGin if r.is_err() { 42*863a3cffSLoGin return; 43*863a3cffSLoGin } 44*863a3cffSLoGin // call function 45*863a3cffSLoGin f(); 46*863a3cffSLoGin // set completed 47*863a3cffSLoGin self.inner.store(OnceState::Complete, Ordering::SeqCst); 48*863a3cffSLoGin } 49*863a3cffSLoGin 50*863a3cffSLoGin /// Performs the same function as [`call_once()`] except ignores poisoning. 51*863a3cffSLoGin /// 52*863a3cffSLoGin /// Unlike [`call_once()`], if this [`Once`] has been poisoned (i.e., a previous 53*863a3cffSLoGin /// call to [`call_once()`] or [`call_once_force()`] caused a panic), calling 54*863a3cffSLoGin /// [`call_once_force()`] will still invoke the closure `f` and will _not_ 55*863a3cffSLoGin /// result in an immediate panic. If `f` panics, the [`Once`] will remain 56*863a3cffSLoGin /// in a poison state. If `f` does _not_ panic, the [`Once`] will no 57*863a3cffSLoGin /// longer be in a poison state and all future calls to [`call_once()`] or 58*863a3cffSLoGin /// [`call_once_force()`] will be no-ops. 59*863a3cffSLoGin /// 60*863a3cffSLoGin /// The closure `f` is yielded a [`OnceState`] structure which can be used 61*863a3cffSLoGin /// to query the poison status of the [`Once`]. 62*863a3cffSLoGin /// 63*863a3cffSLoGin /// [`call_once()`]: Once::call_once 64*863a3cffSLoGin /// [`call_once_force()`]: Once::call_once_force 65*863a3cffSLoGin /// 66*863a3cffSLoGin /// # Examples 67*863a3cffSLoGin /// 68*863a3cffSLoGin /// ``` 69*863a3cffSLoGin /// use std::sync::Once; 70*863a3cffSLoGin /// use std::thread; 71*863a3cffSLoGin /// 72*863a3cffSLoGin /// static INIT: Once = Once::new(); 73*863a3cffSLoGin /// 74*863a3cffSLoGin /// // poison the once 75*863a3cffSLoGin /// let handle = thread::spawn(|| { 76*863a3cffSLoGin /// INIT.call_once(|| panic!()); 77*863a3cffSLoGin /// }); 78*863a3cffSLoGin /// assert!(handle.join().is_err()); 79*863a3cffSLoGin /// 80*863a3cffSLoGin /// // poisoning propagates 81*863a3cffSLoGin /// let handle = thread::spawn(|| { 82*863a3cffSLoGin /// INIT.call_once(|| {}); 83*863a3cffSLoGin /// }); 84*863a3cffSLoGin /// assert!(handle.join().is_err()); 85*863a3cffSLoGin /// 86*863a3cffSLoGin /// // call_once_force will still run and reset the poisoned state 87*863a3cffSLoGin /// INIT.call_once_force(|state| { 88*863a3cffSLoGin /// assert!(state.is_poisoned()); 89*863a3cffSLoGin /// }); 90*863a3cffSLoGin /// 91*863a3cffSLoGin /// // once any success happens, we stop propagating the poison 92*863a3cffSLoGin /// INIT.call_once(|| {}); 93*863a3cffSLoGin /// ``` call_once_force<F>(&self, f: F) where F: FnOnce(&OnceState),94*863a3cffSLoGin pub fn call_once_force<F>(&self, f: F) 95*863a3cffSLoGin where 96*863a3cffSLoGin F: FnOnce(&OnceState), 97*863a3cffSLoGin { 98*863a3cffSLoGin // fast path check 99*863a3cffSLoGin if self.is_completed() { 100*863a3cffSLoGin return; 101*863a3cffSLoGin } 102*863a3cffSLoGin 103*863a3cffSLoGin // set poisoned 104*863a3cffSLoGin self.inner 105*863a3cffSLoGin .compare_exchange( 106*863a3cffSLoGin OnceState::Incomplete, 107*863a3cffSLoGin OnceState::Posioned, 108*863a3cffSLoGin Ordering::SeqCst, 109*863a3cffSLoGin Ordering::SeqCst, 110*863a3cffSLoGin ) 111*863a3cffSLoGin .ok(); 112*863a3cffSLoGin 113*863a3cffSLoGin // call function 114*863a3cffSLoGin f(&self.inner.load(Ordering::SeqCst)); 115*863a3cffSLoGin 116*863a3cffSLoGin // set initialized 117*863a3cffSLoGin self.inner.store(OnceState::Complete, Ordering::SeqCst); 118*863a3cffSLoGin } 119*863a3cffSLoGin 120*863a3cffSLoGin /// Fast path check 121*863a3cffSLoGin #[inline] is_completed(&self) -> bool122*863a3cffSLoGin pub fn is_completed(&self) -> bool { 123*863a3cffSLoGin self.inner.load(Ordering::SeqCst) == OnceState::Complete 124*863a3cffSLoGin } 125*863a3cffSLoGin 126*863a3cffSLoGin /// Returns the current state of the `Once` instance. 127*863a3cffSLoGin #[inline] state(&self) -> OnceState128*863a3cffSLoGin pub fn state(&self) -> OnceState { 129*863a3cffSLoGin self.inner.load(Ordering::SeqCst) 130*863a3cffSLoGin } 131*863a3cffSLoGin } 132*863a3cffSLoGin 133*863a3cffSLoGin impl Debug for Once { fmt(&self, f: &mut Formatter<'_>) -> fmt::Result134*863a3cffSLoGin fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 135*863a3cffSLoGin f.debug_struct("Once").finish_non_exhaustive() 136*863a3cffSLoGin } 137*863a3cffSLoGin } 138*863a3cffSLoGin 139*863a3cffSLoGin #[allow(dead_code)] 140*863a3cffSLoGin impl OnceState { 141*863a3cffSLoGin /// Returns `true` if the associated [`Once`] was poisoned prior to the 142*863a3cffSLoGin /// invocation of the closure passed to [`Once::call_once_force()`]. 143*863a3cffSLoGin /// 144*863a3cffSLoGin /// # Examples 145*863a3cffSLoGin /// 146*863a3cffSLoGin /// A poisoned [`Once`]: 147*863a3cffSLoGin /// 148*863a3cffSLoGin /// ``` 149*863a3cffSLoGin /// use std::sync::Once; 150*863a3cffSLoGin /// use std::thread; 151*863a3cffSLoGin /// 152*863a3cffSLoGin /// static INIT: Once = Once::new(); 153*863a3cffSLoGin /// 154*863a3cffSLoGin /// // poison the once 155*863a3cffSLoGin /// let handle = thread::spawn(|| { 156*863a3cffSLoGin /// INIT.call_once(|| panic!()); 157*863a3cffSLoGin /// }); 158*863a3cffSLoGin /// assert!(handle.join().is_err()); 159*863a3cffSLoGin /// 160*863a3cffSLoGin /// INIT.call_once_force(|state| { 161*863a3cffSLoGin /// assert!(state.is_poisoned()); 162*863a3cffSLoGin /// }); 163*863a3cffSLoGin /// ``` 164*863a3cffSLoGin /// 165*863a3cffSLoGin /// An unpoisoned [`Once`]: 166*863a3cffSLoGin /// 167*863a3cffSLoGin /// ``` 168*863a3cffSLoGin /// use std::sync::Once; 169*863a3cffSLoGin /// 170*863a3cffSLoGin /// static INIT: Once = Once::new(); 171*863a3cffSLoGin /// 172*863a3cffSLoGin /// INIT.call_once_force(|state| { 173*863a3cffSLoGin /// assert!(!state.is_poisoned()); 174*863a3cffSLoGin /// }); 175*863a3cffSLoGin #[inline] is_poisoned(&self) -> bool176*863a3cffSLoGin pub fn is_poisoned(&self) -> bool { 177*863a3cffSLoGin *self == OnceState::Posioned 178*863a3cffSLoGin } 179*863a3cffSLoGin } 180