Skip to content

Commit 681aafa

Browse files
authored
Make AtomicRef::new const fn (#2)
The implementation is possible to write in stable rust since rustc 1.46.0. This patch also removes the now-unnecessary `ATOMIC_U8_REF_INIT` const and `static_atomic_ref` macro.
1 parent c5f2896 commit 681aafa

File tree

1 file changed

+20
-103
lines changed

1 file changed

+20
-103
lines changed

src/lib.rs

Lines changed: 20 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@
3939
//! }
4040
//!
4141
//! // The methods for working with our currently defined static logger
42-
//! static_atomic_ref! {
43-
//! static LOGGER: AtomicRef<LoggerInfo>;
44-
//! }
42+
//! static LOGGER: AtomicRef<LoggerInfo> = AtomicRef::new(None);
4543
//! fn log(msg: &str) -> bool {
4644
//! if let Some(info) = LOGGER.load(Ordering::SeqCst) {
4745
//! info.logger.log(msg);
@@ -73,117 +71,37 @@
7371
//! ```
7472
#![no_std]
7573

76-
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
74+
use core::sync::atomic::{AtomicPtr, Ordering};
7775
use core::marker::PhantomData;
7876
use core::fmt;
77+
use core::ptr::null_mut;
7978
use core::default::Default;
8079

8180
/// A mutable Option<&'a, T> type which can be safely shared between threads.
8281
#[repr(C)]
8382
pub struct AtomicRef<'a, T: 'a> {
84-
data: AtomicUsize,
83+
data: AtomicPtr<T>,
8584
// Make `AtomicRef` invariant over `'a` and `T`
86-
_marker: PhantomData<&'a mut &'a mut T>,
85+
_marker: PhantomData<Invariant<'a, T>>,
8786
}
8887

89-
/// You will probably never need to use this type. It exists mostly for internal
90-
/// use in the `static_atomic_ref!` macro.
91-
///
92-
/// Unlike `AtomicUsize` and its ilk, we cannot have an `ATOMIC_REF_INIT` const
93-
/// which is initialized to `None`, as constants cannot be generic over a type
94-
/// parameter. This is the same reason why `AtomicPtr` does not have an
95-
/// `ATOMIC_PTR_INIT` const.
96-
///
97-
/// Instead, we have a single const for `&'static u8`, and take advantage of the
98-
/// fact that all AtomicRef types have identical layout to implement the
99-
/// `static_atomic_ref!` macro.
100-
///
101-
/// Please use `static_atomic_ref!` instead of this constant if you need to
102-
/// implement a static atomic reference variable.
103-
pub const ATOMIC_U8_REF_INIT: AtomicRef<'static, u8> = AtomicRef {
104-
data: ATOMIC_USIZE_INIT,
105-
_marker: PhantomData,
106-
};
107-
108-
/// Re-export `core` for `static_atomic_ref!` (which may be used in a
109-
/// non-`no_std` crate, where `core` is unavailable).
110-
#[doc(hidden)]
111-
pub use core::{mem as core_mem, ops as core_ops};
88+
// Work-around for the construction of `PhantomData<&mut _>` requiring
89+
// `#![feature(const_fn)]`
90+
struct Invariant<'a, T: 'a>(&'a mut &'a mut T);
11291

113-
/// A macro to define a statically allocated `AtomicRef<'static, T>` which is
114-
/// initialized to `None`.
115-
///
116-
/// # Examples
117-
///
118-
/// ```
119-
/// # #[macro_use]
120-
/// # extern crate atomic_ref;
121-
/// use std::sync::atomic::Ordering;
122-
///
123-
/// static_atomic_ref! {
124-
/// static SOME_REFERENCE: AtomicRef<i32>;
125-
/// pub static PUB_REFERENCE: AtomicRef<u64>;
126-
/// }
127-
///
128-
/// fn main() {
129-
/// let a: Option<&'static i32> = SOME_REFERENCE.load(Ordering::SeqCst);
130-
/// assert_eq!(a, None);
131-
/// }
132-
/// ```
133-
#[macro_export]
134-
macro_rules! static_atomic_ref {
135-
($(#[$attr:meta])* static $N:ident : AtomicRef<$T:ty>; $($t:tt)*) => {
136-
static_atomic_ref!(@PRIV, $(#[$attr])* static $N : $T; $($t)*);
137-
};
138-
($(#[$attr:meta])* pub static $N:ident : AtomicRef<$T:ty>; $($t:tt)*) => {
139-
static_atomic_ref!(@PUB, $(#[$attr])* static $N : $T; $($t)*);
140-
};
141-
(@$VIS:ident, $(#[$attr:meta])* static $N:ident : $T:ty; $($t:tt)*) => {
142-
static_atomic_ref!(@MAKE TY, $VIS, $(#[$attr])*, $N);
143-
impl $crate::core_ops::Deref for $N {
144-
type Target = $crate::AtomicRef<'static, $T>;
145-
#[allow(unsafe_code)]
146-
fn deref<'a>(&'a self) -> &'a $crate::AtomicRef<'static, $T> {
147-
static STORAGE: $crate::AtomicRef<'static, u8> = $crate::ATOMIC_U8_REF_INIT;
148-
unsafe { $crate::core_mem::transmute(&STORAGE) }
149-
}
150-
}
151-
static_atomic_ref!($($t)*);
152-
};
153-
(@MAKE TY, PUB, $(#[$attr:meta])*, $N:ident) => {
154-
#[allow(missing_copy_implementations)]
155-
#[allow(non_camel_case_types)]
156-
#[allow(dead_code)]
157-
$(#[$attr])*
158-
pub struct $N { _private: () }
159-
#[doc(hidden)]
160-
pub static $N: $N = $N { _private: () };
161-
};
162-
(@MAKE TY, PRIV, $(#[$attr:meta])*, $N:ident) => {
163-
#[allow(missing_copy_implementations)]
164-
#[allow(non_camel_case_types)]
165-
#[allow(dead_code)]
166-
$(#[$attr])*
167-
struct $N { _private: () }
168-
#[doc(hidden)]
169-
static $N: $N = $N { _private: () };
170-
};
171-
() => ();
172-
}
173-
174-
/// An internal helper function for converting `Option<&'a T>` values to usize
175-
/// for storing in the `AtomicUsize`.
176-
fn from_opt<'a, T>(p: Option<&'a T>) -> usize {
92+
/// An internal helper function for converting `Option<&'a T>` values to
93+
/// `*mut T` for storing in the `AtomicUsize`.
94+
const fn from_opt<'a, T>(p: Option<&'a T>) -> *mut T {
17795
match p {
178-
Some(p) => p as *const T as usize,
179-
None => 0,
96+
Some(p) => p as *const T as *mut T,
97+
None => null_mut(),
18098
}
18199
}
182100

183-
/// An internal helper function for converting `usize` values stored in the
101+
/// An internal helper function for converting `*mut T` values stored in the
184102
/// `AtomicUsize` back into `Option<&'a T>` values.
185-
unsafe fn to_opt<'a, T>(p: usize) -> Option<&'a T> {
186-
(p as *const T).as_ref()
103+
unsafe fn to_opt<'a, T>(p: *mut T) -> Option<&'a T> {
104+
p.as_ref()
187105
}
188106

189107
impl<'a, T> AtomicRef<'a, T> {
@@ -197,9 +115,9 @@ impl<'a, T> AtomicRef<'a, T> {
197115
/// static VALUE: i32 = 10;
198116
/// let atomic_ref = AtomicRef::new(Some(&VALUE));
199117
/// ```
200-
pub fn new(p: Option<&'a T>) -> AtomicRef<'a, T> {
118+
pub const fn new(p: Option<&'a T>) -> AtomicRef<'a, T> {
201119
AtomicRef {
202-
data: AtomicUsize::new(from_opt(p)),
120+
data: AtomicPtr::new(from_opt(p)),
203121
_marker: PhantomData,
204122
}
205123
}
@@ -410,10 +328,9 @@ impl<'a, T> Default for AtomicRef<'a, T> {
410328
#[cfg(test)]
411329
mod tests {
412330
use core::sync::atomic::Ordering;
331+
use super::AtomicRef;
413332

414-
static_atomic_ref! {
415-
static FOO: AtomicRef<i32>;
416-
}
333+
static FOO: AtomicRef<i32> = AtomicRef::new(None);
417334

418335
static A: i32 = 10;
419336

0 commit comments

Comments
 (0)