@@ -24,10 +24,11 @@ use atomic_polyfill as atomic;
2424#[ cfg( not( feature = "critical-section" ) ) ]
2525use core:: sync:: atomic;
2626
27- use atomic:: { AtomicUsize , Ordering } ;
27+ use atomic:: { AtomicPtr , AtomicUsize , Ordering } ;
2828use core:: cell:: UnsafeCell ;
2929use core:: marker:: PhantomData ;
3030use core:: num:: NonZeroUsize ;
31+ use core:: ptr;
3132
3233/// A thread-safe cell which can be written to only once.
3334#[ derive( Default , Debug ) ]
@@ -176,7 +177,7 @@ impl OnceBool {
176177
177178/// A thread-safe cell which can be written to only once.
178179pub struct OnceRef < ' a , T > {
179- inner : OnceNonZeroUsize ,
180+ inner : AtomicPtr < T > ,
180181 ghost : PhantomData < UnsafeCell < & ' a T > > ,
181182}
182183
@@ -198,21 +199,27 @@ impl<'a, T> Default for OnceRef<'a, T> {
198199impl < ' a , T > OnceRef < ' a , T > {
199200 /// Creates a new empty cell.
200201 pub const fn new ( ) -> OnceRef < ' a , T > {
201- OnceRef { inner : OnceNonZeroUsize :: new ( ) , ghost : PhantomData }
202+ OnceRef { inner : AtomicPtr :: new ( ptr :: null_mut ( ) ) , ghost : PhantomData }
202203 }
203204
204205 /// Gets a reference to the underlying value.
205206 pub fn get ( & self ) -> Option < & ' a T > {
206- self . inner . get ( ) . map ( |ptr| unsafe { & * ( ptr. get ( ) as * const T ) } )
207+ let ptr = self . inner . load ( Ordering :: Acquire ) ;
208+ unsafe { ptr. as_ref ( ) }
207209 }
208210
209211 /// Sets the contents of this cell to `value`.
210212 ///
211213 /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
212214 /// full.
213215 pub fn set ( & self , value : & ' a T ) -> Result < ( ) , ( ) > {
214- let ptr = NonZeroUsize :: new ( value as * const T as usize ) . unwrap ( ) ;
215- self . inner . set ( ptr)
216+ let ptr = value as * const T as * mut T ;
217+ let exchange =
218+ self . inner . compare_exchange ( ptr:: null_mut ( ) , ptr, Ordering :: AcqRel , Ordering :: Acquire ) ;
219+ match exchange {
220+ Ok ( _) => Ok ( ( ) ) ,
221+ Err ( _) => Err ( ( ) ) ,
222+ }
216223 }
217224
218225 /// Gets the contents of the cell, initializing it with `f` if the cell was
@@ -225,9 +232,11 @@ impl<'a, T> OnceRef<'a, T> {
225232 where
226233 F : FnOnce ( ) -> & ' a T ,
227234 {
228- let f = || NonZeroUsize :: new ( f ( ) as * const T as usize ) . unwrap ( ) ;
229- let ptr = self . inner . get_or_init ( f) ;
230- unsafe { & * ( ptr. get ( ) as * const T ) }
235+ enum Void { }
236+ match self . get_or_try_init ( || Ok :: < & ' a T , Void > ( f ( ) ) ) {
237+ Ok ( val) => val,
238+ Err ( void) => match void { } ,
239+ }
231240 }
232241
233242 /// Gets the contents of the cell, initializing it with `f` if
@@ -241,9 +250,23 @@ impl<'a, T> OnceRef<'a, T> {
241250 where
242251 F : FnOnce ( ) -> Result < & ' a T , E > ,
243252 {
244- let f = || f ( ) . map ( |value| NonZeroUsize :: new ( value as * const T as usize ) . unwrap ( ) ) ;
245- let ptr = self . inner . get_or_try_init ( f) ?;
246- unsafe { Ok ( & * ( ptr. get ( ) as * const T ) ) }
253+ let mut ptr = self . inner . load ( Ordering :: Acquire ) ;
254+
255+ if ptr. is_null ( ) {
256+ // TODO replace with `cast_mut` when MSRV reaches 1.65.0 (also in `set`)
257+ ptr = f ( ) ? as * const T as * mut T ;
258+ let exchange = self . inner . compare_exchange (
259+ ptr:: null_mut ( ) ,
260+ ptr,
261+ Ordering :: AcqRel ,
262+ Ordering :: Acquire ,
263+ ) ;
264+ if let Err ( old) = exchange {
265+ ptr = old;
266+ }
267+ }
268+
269+ Ok ( unsafe { & * ptr } )
247270 }
248271
249272 /// ```compile_fail
0 commit comments