Skip to content

Commit 2a965b0

Browse files
author
Thom Chiovoloni
committed
Add a AtomicRef::static_some function allowing providing a non-empty initial value
1 parent ffb8aba commit 2a965b0

File tree

1 file changed

+45
-9
lines changed

1 file changed

+45
-9
lines changed

src/lib.rs

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,16 @@
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;
7778
use core::marker::PhantomData;
7879
use core::fmt;
7980
use core::default::Default;
8081

8182
/// A mutable Option<&'a, T> type which can be safely shared between threads.
8283
#[repr(C)]
8384
pub 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.
103104
pub 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

197223
impl<'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

Comments
 (0)