@@ -24,10 +24,11 @@ use atomic_polyfill as atomic;
24
24
#[ cfg( not( feature = "critical-section" ) ) ]
25
25
use core:: sync:: atomic;
26
26
27
- use atomic:: { AtomicUsize , Ordering } ;
27
+ use atomic:: { AtomicPtr , AtomicUsize , Ordering } ;
28
28
use core:: cell:: UnsafeCell ;
29
29
use core:: marker:: PhantomData ;
30
30
use core:: num:: NonZeroUsize ;
31
+ use core:: ptr;
31
32
32
33
/// A thread-safe cell which can be written to only once.
33
34
#[ derive( Default , Debug ) ]
@@ -176,7 +177,7 @@ impl OnceBool {
176
177
177
178
/// A thread-safe cell which can be written to only once.
178
179
pub struct OnceRef < ' a , T > {
179
- inner : OnceNonZeroUsize ,
180
+ inner : AtomicPtr < T > ,
180
181
ghost : PhantomData < UnsafeCell < & ' a T > > ,
181
182
}
182
183
@@ -198,21 +199,27 @@ impl<'a, T> Default for OnceRef<'a, T> {
198
199
impl < ' a , T > OnceRef < ' a , T > {
199
200
/// Creates a new empty cell.
200
201
pub const fn new ( ) -> OnceRef < ' a , T > {
201
- OnceRef { inner : OnceNonZeroUsize :: new ( ) , ghost : PhantomData }
202
+ OnceRef { inner : AtomicPtr :: new ( ptr :: null_mut ( ) ) , ghost : PhantomData }
202
203
}
203
204
204
205
/// Gets a reference to the underlying value.
205
206
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 ( ) }
207
209
}
208
210
209
211
/// Sets the contents of this cell to `value`.
210
212
///
211
213
/// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
212
214
/// full.
213
215
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
+ }
216
223
}
217
224
218
225
/// Gets the contents of the cell, initializing it with `f` if the cell was
@@ -225,9 +232,11 @@ impl<'a, T> OnceRef<'a, T> {
225
232
where
226
233
F : FnOnce ( ) -> & ' a T ,
227
234
{
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
+ }
231
240
}
232
241
233
242
/// Gets the contents of the cell, initializing it with `f` if
@@ -241,9 +250,23 @@ impl<'a, T> OnceRef<'a, T> {
241
250
where
242
251
F : FnOnce ( ) -> Result < & ' a T , E > ,
243
252
{
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 } )
247
270
}
248
271
249
272
/// ```compile_fail
0 commit comments