7373//! ```
7474#![ no_std]
7575
76- use core:: sync:: atomic:: { AtomicUsize , ATOMIC_USIZE_INIT , Ordering } ;
76+ use core:: sync:: atomic:: { AtomicPtr , Ordering } ;
77+ use core:: ptr:: null_mut;
7778use core:: marker:: PhantomData ;
7879use core:: fmt;
7980use core:: default:: Default ;
8081
8182/// A mutable Option<&'a, T> type which can be safely shared between threads.
8283#[ repr( C ) ]
8384pub struct AtomicRef < ' a , T : ' a > {
84- data : AtomicUsize ,
85+ data : AtomicPtr < T > ,
8586 // Make `AtomicRef` invariant over `'a` and `T`
8687 _marker : PhantomData < & ' a mut & ' a mut T > ,
8788}
@@ -101,7 +102,7 @@ pub struct AtomicRef<'a, T: 'a> {
101102/// Please use `static_atomic_ref!` instead of this constant if you need to
102103/// implement a static atomic reference variable.
103104pub const ATOMIC_U8_REF_INIT : AtomicRef < ' static , u8 > = AtomicRef {
104- data : ATOMIC_USIZE_INIT ,
105+ data : AtomicPtr :: new ( null_mut ( ) ) ,
105106 _marker : PhantomData ,
106107} ;
107108
@@ -155,16 +156,16 @@ macro_rules! static_atomic_ref {
155156
156157/// An internal helper function for converting `Option<&'a T>` values to usize
157158/// for storing in the `AtomicUsize`.
158- fn from_opt < ' a , T > ( p : Option < & ' a T > ) -> usize {
159+ fn from_opt < ' a , T > ( p : Option < & ' a T > ) -> * mut T {
159160 match p {
160- Some ( p) => p as * const T as usize ,
161- None => 0 ,
161+ Some ( p) => p as * const T as * mut T ,
162+ None => null_mut ( ) ,
162163 }
163164}
164165
165166/// An internal helper function for converting `usize` values stored in the
166167/// `AtomicUsize` back into `Option<&'a T>` values.
167- unsafe fn to_opt < ' a , T > ( p : usize ) -> Option < & ' a T > {
168+ unsafe fn to_opt < ' a , T > ( p : * mut T ) -> Option < & ' a T > {
168169 ( p as * const T ) . as_ref ( )
169170}
170171
@@ -173,7 +174,7 @@ impl<T: 'static> AtomicRef<'static, T> {
173174 // fn" limitation, because of the `PhantomData`. Other methods of enforcing
174175 // invariance hit the same sort of problem (`fn` isn't allowed either).
175176 const NONE : Self = Self {
176- data : AtomicUsize :: new ( 0 ) ,
177+ data : AtomicPtr :: new ( null_mut ( ) ) ,
177178 _marker : PhantomData ,
178179 } ;
179180 /// Returns a `AtomicRef<'static, T>` with a value of `None`.
@@ -192,6 +193,31 @@ impl<T: 'static> AtomicRef<'static, T> {
192193 pub const fn static_none ( ) -> Self {
193194 Self :: NONE
194195 }
196+
197+ /// Returns a `AtomicRef<'static, T>` with a value of `Some(arg)`.
198+ ///
199+ /// This is useful as it is implemented as a `const fn`, and thus can
200+ /// initialize an `AtomicRef` used as a `static`.
201+ ///
202+ /// # Examples
203+ ///
204+ /// ```
205+ /// use atomic_ref::AtomicRef;
206+ /// use std::sync::atomic::Ordering;
207+ ///
208+ /// static INITIAL: u64 = 123;
209+ ///
210+ /// pub static SOME_REFERENCE: AtomicRef<'static, u64> = AtomicRef::static_some(&INITIAL);
211+ ///
212+ /// assert_eq!(Some(&123), SOME_REFERENCE.load(Ordering::SeqCst));
213+ /// ```
214+ #[ inline]
215+ pub const fn static_some ( init : & ' static T ) -> Self {
216+ Self {
217+ data : AtomicPtr :: new ( init as * const T as * mut T ) ,
218+ ..Self :: NONE
219+ }
220+ }
195221}
196222
197223impl < ' a , T > AtomicRef < ' a , T > {
@@ -207,7 +233,7 @@ impl<'a, T> AtomicRef<'a, T> {
207233 /// ```
208234 pub fn new ( p : Option < & ' a T > ) -> AtomicRef < ' a , T > {
209235 AtomicRef {
210- data : AtomicUsize :: new ( from_opt ( p) ) ,
236+ data : AtomicPtr :: new ( from_opt ( p) ) ,
211237 _marker : PhantomData ,
212238 }
213239 }
@@ -432,4 +458,14 @@ mod tests {
432458 assert ! ( FOO . load( Ordering :: SeqCst ) == Some ( & A ) ) ;
433459 assert ! ( FOO . load( Ordering :: SeqCst ) . unwrap( ) as * const _ == & A as * const _) ;
434460 }
461+
462+ static BAR : super :: AtomicRef < ' static , i32 > = super :: AtomicRef :: static_some ( & A ) ;
463+
464+ #[ test]
465+ fn static_some ( ) {
466+ assert_eq ! ( BAR . load( Ordering :: SeqCst ) , Some ( & 10 ) ) ;
467+ assert_eq ! ( BAR . load( Ordering :: SeqCst ) . unwrap( ) as * const _, & A as * const _) ;
468+ BAR . store ( None , Ordering :: SeqCst ) ;
469+ assert_eq ! ( BAR . load( Ordering :: SeqCst ) , None ) ;
470+ }
435471}
0 commit comments