From 5ac7a90089dbe3807934deebc6d7b403e60eba05 Mon Sep 17 00:00:00 2001 From: yvt Date: Sun, 7 Jun 2020 14:42:46 +0900 Subject: [PATCH 1/9] Implement an alternative solution for the variance issue not involving `Mutex` --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3d6da24..6f2bec5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,7 +72,6 @@ //! } //! ``` -use std::sync::Mutex; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use std::marker::PhantomData; use std::fmt; @@ -82,7 +81,8 @@ use std::default::Default; #[repr(C)] pub struct AtomicRef<'a, T: 'a> { data: AtomicUsize, - _marker: PhantomData>, + // Make `AtomicRef` invariant over `'a` and `T` + _marker: PhantomData<&'a mut &'a mut T>, } /// You will probably never need to use this type. It exists mostly for internal From cb4e7c5cb94ef83374bfd31073f230e288880211 Mon Sep 17 00:00:00 2001 From: yvt Date: Sun, 7 Jun 2020 14:48:03 +0900 Subject: [PATCH 2/9] Get rid of dependency on `std` --- src/lib.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6f2bec5..777475a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,11 +71,12 @@ //! assert!(res); //! } //! ``` +#![no_std] -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; -use std::marker::PhantomData; -use std::fmt; -use std::default::Default; +use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use core::marker::PhantomData; +use core::fmt; +use core::default::Default; /// A mutable Option<&'a, T> type which can be safely shared between threads. #[repr(C)] @@ -104,6 +105,11 @@ pub const ATOMIC_U8_REF_INIT: AtomicRef<'static, u8> = AtomicRef { _marker: PhantomData, }; +/// Re-export `core` for `static_atomic_ref!` (which may be used in a +/// non-`no_std` crate, where `core` is unavailable). +#[doc(hidden)] +pub use core::{mem as core_mem, ops as core_ops}; + /// A macro to define a statically allocated `AtomicRef<'static, T>` which is /// initialized to `None`. /// @@ -134,12 +140,12 @@ macro_rules! static_atomic_ref { }; (@$VIS:ident, $(#[$attr:meta])* static $N:ident : $T:ty; $($t:tt)*) => { static_atomic_ref!(@MAKE TY, $VIS, $(#[$attr])*, $N); - impl ::std::ops::Deref for $N { + impl $crate::core_ops::Deref for $N { type Target = $crate::AtomicRef<'static, $T>; #[allow(unsafe_code)] fn deref<'a>(&'a self) -> &'a $crate::AtomicRef<'static, $T> { static STORAGE: $crate::AtomicRef<'static, u8> = $crate::ATOMIC_U8_REF_INIT; - unsafe { ::std::mem::transmute(&STORAGE) } + unsafe { $crate::core_mem::transmute(&STORAGE) } } } static_atomic_ref!($($t)*); @@ -403,7 +409,7 @@ impl<'a, T> Default for AtomicRef<'a, T> { #[cfg(test)] mod tests { - use std::sync::atomic::Ordering; + use core::sync::atomic::Ordering; static_atomic_ref! { static FOO: AtomicRef; From fd4c68e56191514011422c2721e3bdd5d1c37173 Mon Sep 17 00:00:00 2001 From: yvt Date: Sun, 7 Jun 2020 14:20:08 +0900 Subject: [PATCH 3/9] Replace `AtomicUsize` with `AtomicPtr` Raises the minimum supported Rust version to 1.32.0. --- src/lib.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 777475a..900a5a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,15 +73,16 @@ //! ``` #![no_std] -use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use core::sync::atomic::{AtomicPtr, Ordering}; use core::marker::PhantomData; use core::fmt; +use core::ptr::null_mut; use core::default::Default; /// A mutable Option<&'a, T> type which can be safely shared between threads. #[repr(C)] pub struct AtomicRef<'a, T: 'a> { - data: AtomicUsize, + data: AtomicPtr, // Make `AtomicRef` invariant over `'a` and `T` _marker: PhantomData<&'a mut &'a mut T>, } @@ -101,7 +102,7 @@ pub struct AtomicRef<'a, T: 'a> { /// Please use `static_atomic_ref!` instead of this constant if you need to /// implement a static atomic reference variable. pub const ATOMIC_U8_REF_INIT: AtomicRef<'static, u8> = AtomicRef { - data: ATOMIC_USIZE_INIT, + data: AtomicPtr::new(null_mut()), _marker: PhantomData, }; @@ -171,19 +172,19 @@ macro_rules! static_atomic_ref { () => (); } -/// An internal helper function for converting `Option<&'a T>` values to usize -/// for storing in the `AtomicUsize`. -fn from_opt<'a, T>(p: Option<&'a T>) -> usize { +/// An internal helper function for converting `Option<&'a T>` values to +/// `*mut T` for storing in the `AtomicUsize`. +fn from_opt<'a, T>(p: Option<&'a T>) -> *mut T { match p { - Some(p) => p as *const T as usize, - None => 0, + Some(p) => p as *const T as *mut T, + None => null_mut(), } } -/// An internal helper function for converting `usize` values stored in the +/// An internal helper function for converting `*mut T` values stored in the /// `AtomicUsize` back into `Option<&'a T>` values. -unsafe fn to_opt<'a, T>(p: usize) -> Option<&'a T> { - (p as *const T).as_ref() +unsafe fn to_opt<'a, T>(p: *mut T) -> Option<&'a T> { + p.as_ref() } impl<'a, T> AtomicRef<'a, T> { @@ -199,7 +200,7 @@ impl<'a, T> AtomicRef<'a, T> { /// ``` pub fn new(p: Option<&'a T>) -> AtomicRef<'a, T> { AtomicRef { - data: AtomicUsize::new(from_opt(p)), + data: AtomicPtr::new(from_opt(p)), _marker: PhantomData, } } From 0c4106ecd98463da4a218d847beab82da805e650 Mon Sep 17 00:00:00 2001 From: yvt Date: Sun, 7 Jun 2020 14:33:35 +0900 Subject: [PATCH 4/9] Make `AtomicRef::new` `const fn` Requires the following unstable features: - `const_fn` for constructing `PhantomData<&mut _>` - `const_if_match` for using `match` in a user-defined `const fn` --- src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 900a5a6..515dc12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,6 +72,8 @@ //! } //! ``` #![no_std] +#![feature(const_fn)] +#![feature(const_if_match)] use core::sync::atomic::{AtomicPtr, Ordering}; use core::marker::PhantomData; @@ -174,7 +176,7 @@ macro_rules! static_atomic_ref { /// An internal helper function for converting `Option<&'a T>` values to /// `*mut T` for storing in the `AtomicUsize`. -fn from_opt<'a, T>(p: Option<&'a T>) -> *mut T { +const fn from_opt<'a, T>(p: Option<&'a T>) -> *mut T { match p { Some(p) => p as *const T as *mut T, None => null_mut(), @@ -198,7 +200,7 @@ impl<'a, T> AtomicRef<'a, T> { /// static VALUE: i32 = 10; /// let atomic_ref = AtomicRef::new(Some(&VALUE)); /// ``` - pub fn new(p: Option<&'a T>) -> AtomicRef<'a, T> { + pub const fn new(p: Option<&'a T>) -> AtomicRef<'a, T> { AtomicRef { data: AtomicPtr::new(from_opt(p)), _marker: PhantomData, From 97dc28c67f56b03d998a8a296cf3ff9cc728af45 Mon Sep 17 00:00:00 2001 From: yvt Date: Sun, 7 Jun 2020 15:13:22 +0900 Subject: [PATCH 5/9] Make the use of unstable features non-mandatory --- Cargo.toml | 4 ++++ src/lib.rs | 69 +++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cf50686..0dc6095 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,8 @@ readme = "README.md" license = "MIT" keywords = ["atomic", "reference", "static"] +[features] +default = [] +nightly = [] + [dependencies] diff --git a/src/lib.rs b/src/lib.rs index 515dc12..80bd866 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,9 +71,15 @@ //! assert!(res); //! } //! ``` +//! +//! # Cargo Features +//! +//! - `nightly` enables the use of unstable features. Turns [`AtomicRef::new`] +//! into `const fn`, making it callable in constant contexts. +//! #![no_std] -#![feature(const_fn)] -#![feature(const_if_match)] +#![cfg_attr(feature = "nightly", feature(const_fn))] +#![cfg_attr(feature = "nightly", feature(const_if_match))] use core::sync::atomic::{AtomicPtr, Ordering}; use core::marker::PhantomData; @@ -174,12 +180,29 @@ macro_rules! static_atomic_ref { () => (); } -/// An internal helper function for converting `Option<&'a T>` values to -/// `*mut T` for storing in the `AtomicUsize`. -const fn from_opt<'a, T>(p: Option<&'a T>) -> *mut T { - match p { - Some(p) => p as *const T as *mut T, - None => null_mut(), +macro_rules! const_fn_if_nightly { + ( + $( #[$meta:meta] )* + $vis:vis fn $($rest:tt)* + ) => { + $( #[$meta] )* + #[cfg(feature = "nightly")] + $vis const fn $($rest)* + + $( #[$meta] )* + #[cfg(not(feature = "nightly"))] + $vis fn $($rest)* + }; +} + +const_fn_if_nightly! { + /// An internal helper function for converting `Option<&'a T>` values to + /// `*mut T` for storing in the `AtomicUsize`. + fn from_opt<'a, T>(p: Option<&'a T>) -> *mut T { + match p { + Some(p) => p as *const T as *mut T, + None => null_mut(), + } } } @@ -190,20 +213,22 @@ unsafe fn to_opt<'a, T>(p: *mut T) -> Option<&'a T> { } impl<'a, T> AtomicRef<'a, T> { - /// Creates a new `AtomicRef`. - /// - /// # Examples - /// - /// ``` - /// use atomic_ref::AtomicRef; - /// - /// static VALUE: i32 = 10; - /// let atomic_ref = AtomicRef::new(Some(&VALUE)); - /// ``` - pub const fn new(p: Option<&'a T>) -> AtomicRef<'a, T> { - AtomicRef { - data: AtomicPtr::new(from_opt(p)), - _marker: PhantomData, + const_fn_if_nightly! { + /// Creates a new `AtomicRef`. + /// + /// # Examples + /// + /// ``` + /// use atomic_ref::AtomicRef; + /// + /// static VALUE: i32 = 10; + /// let atomic_ref = AtomicRef::new(Some(&VALUE)); + /// ``` + pub fn new(p: Option<&'a T>) -> AtomicRef<'a, T> { + AtomicRef { + data: AtomicPtr::new(from_opt(p)), + _marker: PhantomData, + } } } From 37523c17a2a535f4d04c204d65d2742647abed25 Mon Sep 17 00:00:00 2001 From: yvt Date: Sun, 7 Jun 2020 15:18:15 +0900 Subject: [PATCH 6/9] Unnecessitate `#![feature(const_fn)]` --- src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 80bd866..982e6be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,7 +78,6 @@ //! into `const fn`, making it callable in constant contexts. //! #![no_std] -#![cfg_attr(feature = "nightly", feature(const_fn))] #![cfg_attr(feature = "nightly", feature(const_if_match))] use core::sync::atomic::{AtomicPtr, Ordering}; @@ -92,9 +91,13 @@ use core::default::Default; pub struct AtomicRef<'a, T: 'a> { data: AtomicPtr, // Make `AtomicRef` invariant over `'a` and `T` - _marker: PhantomData<&'a mut &'a mut T>, + _marker: PhantomData>, } +// Work-around for the construction of `PhantomData<&mut _>` requiring +// `#![feature(const_fn)]` +struct Invariant<'a, T: 'a>(&'a mut &'a mut T); + /// You will probably never need to use this type. It exists mostly for internal /// use in the `static_atomic_ref!` macro. /// From 5e5a05703892e0f039500203ca7d1dcc26ed4098 Mon Sep 17 00:00:00 2001 From: yvt Date: Sat, 31 Oct 2020 14:35:44 +0900 Subject: [PATCH 7/9] Remove `nightly` Cargo feature All required unstable features have been stable since Rust version 1.46.0. --- Cargo.toml | 4 ---- src/lib.rs | 67 +++++++++++++++++------------------------------------- 2 files changed, 21 insertions(+), 50 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0dc6095..cf50686 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,4 @@ readme = "README.md" license = "MIT" keywords = ["atomic", "reference", "static"] -[features] -default = [] -nightly = [] - [dependencies] diff --git a/src/lib.rs b/src/lib.rs index 982e6be..d4790b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,14 +71,8 @@ //! assert!(res); //! } //! ``` -//! -//! # Cargo Features -//! -//! - `nightly` enables the use of unstable features. Turns [`AtomicRef::new`] -//! into `const fn`, making it callable in constant contexts. -//! #![no_std] -#![cfg_attr(feature = "nightly", feature(const_if_match))] + use core::sync::atomic::{AtomicPtr, Ordering}; use core::marker::PhantomData; @@ -183,29 +177,12 @@ macro_rules! static_atomic_ref { () => (); } -macro_rules! const_fn_if_nightly { - ( - $( #[$meta:meta] )* - $vis:vis fn $($rest:tt)* - ) => { - $( #[$meta] )* - #[cfg(feature = "nightly")] - $vis const fn $($rest)* - - $( #[$meta] )* - #[cfg(not(feature = "nightly"))] - $vis fn $($rest)* - }; -} - -const_fn_if_nightly! { - /// An internal helper function for converting `Option<&'a T>` values to - /// `*mut T` for storing in the `AtomicUsize`. - fn from_opt<'a, T>(p: Option<&'a T>) -> *mut T { - match p { - Some(p) => p as *const T as *mut T, - None => null_mut(), - } +/// An internal helper function for converting `Option<&'a T>` values to +/// `*mut T` for storing in the `AtomicUsize`. +const fn from_opt<'a, T>(p: Option<&'a T>) -> *mut T { + match p { + Some(p) => p as *const T as *mut T, + None => null_mut(), } } @@ -216,22 +193,20 @@ unsafe fn to_opt<'a, T>(p: *mut T) -> Option<&'a T> { } impl<'a, T> AtomicRef<'a, T> { - const_fn_if_nightly! { - /// Creates a new `AtomicRef`. - /// - /// # Examples - /// - /// ``` - /// use atomic_ref::AtomicRef; - /// - /// static VALUE: i32 = 10; - /// let atomic_ref = AtomicRef::new(Some(&VALUE)); - /// ``` - pub fn new(p: Option<&'a T>) -> AtomicRef<'a, T> { - AtomicRef { - data: AtomicPtr::new(from_opt(p)), - _marker: PhantomData, - } + /// Creates a new `AtomicRef`. + /// + /// # Examples + /// + /// ``` + /// use atomic_ref::AtomicRef; + /// + /// static VALUE: i32 = 10; + /// let atomic_ref = AtomicRef::new(Some(&VALUE)); + /// ``` + pub const fn new(p: Option<&'a T>) -> AtomicRef<'a, T> { + AtomicRef { + data: AtomicPtr::new(from_opt(p)), + _marker: PhantomData, } } From 7b6f17e37fecab550a88f325e9d730bdf5764e8b Mon Sep 17 00:00:00 2001 From: yvt Date: Sat, 31 Oct 2020 14:41:42 +0900 Subject: [PATCH 8/9] Remove `ATOMIC_U8_REF_INIT` and `static_atomic_ref` --- src/lib.rs | 90 ++---------------------------------------------------- 1 file changed, 3 insertions(+), 87 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d4790b1..1bf940f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,9 +39,7 @@ //! } //! //! // The methods for working with our currently defined static logger -//! static_atomic_ref! { -//! static LOGGER: AtomicRef; -//! } +//! static LOGGER: AtomicRef = AtomicRef::new(None); //! fn log(msg: &str) -> bool { //! if let Some(info) = LOGGER.load(Ordering::SeqCst) { //! info.logger.log(msg); @@ -73,7 +71,6 @@ //! ``` #![no_std] - use core::sync::atomic::{AtomicPtr, Ordering}; use core::marker::PhantomData; use core::fmt; @@ -92,91 +89,11 @@ pub struct AtomicRef<'a, T: 'a> { // `#![feature(const_fn)]` struct Invariant<'a, T: 'a>(&'a mut &'a mut T); -/// You will probably never need to use this type. It exists mostly for internal -/// use in the `static_atomic_ref!` macro. -/// -/// Unlike `AtomicUsize` and its ilk, we cannot have an `ATOMIC_REF_INIT` const -/// which is initialized to `None`, as constants cannot be generic over a type -/// parameter. This is the same reason why `AtomicPtr` does not have an -/// `ATOMIC_PTR_INIT` const. -/// -/// Instead, we have a single const for `&'static u8`, and take advantage of the -/// fact that all AtomicRef types have identical layout to implement the -/// `static_atomic_ref!` macro. -/// -/// Please use `static_atomic_ref!` instead of this constant if you need to -/// implement a static atomic reference variable. -pub const ATOMIC_U8_REF_INIT: AtomicRef<'static, u8> = AtomicRef { - data: AtomicPtr::new(null_mut()), - _marker: PhantomData, -}; - /// Re-export `core` for `static_atomic_ref!` (which may be used in a /// non-`no_std` crate, where `core` is unavailable). #[doc(hidden)] pub use core::{mem as core_mem, ops as core_ops}; -/// A macro to define a statically allocated `AtomicRef<'static, T>` which is -/// initialized to `None`. -/// -/// # Examples -/// -/// ``` -/// # #[macro_use] -/// # extern crate atomic_ref; -/// use std::sync::atomic::Ordering; -/// -/// static_atomic_ref! { -/// static SOME_REFERENCE: AtomicRef; -/// pub static PUB_REFERENCE: AtomicRef; -/// } -/// -/// fn main() { -/// let a: Option<&'static i32> = SOME_REFERENCE.load(Ordering::SeqCst); -/// assert_eq!(a, None); -/// } -/// ``` -#[macro_export] -macro_rules! static_atomic_ref { - ($(#[$attr:meta])* static $N:ident : AtomicRef<$T:ty>; $($t:tt)*) => { - static_atomic_ref!(@PRIV, $(#[$attr])* static $N : $T; $($t)*); - }; - ($(#[$attr:meta])* pub static $N:ident : AtomicRef<$T:ty>; $($t:tt)*) => { - static_atomic_ref!(@PUB, $(#[$attr])* static $N : $T; $($t)*); - }; - (@$VIS:ident, $(#[$attr:meta])* static $N:ident : $T:ty; $($t:tt)*) => { - static_atomic_ref!(@MAKE TY, $VIS, $(#[$attr])*, $N); - impl $crate::core_ops::Deref for $N { - type Target = $crate::AtomicRef<'static, $T>; - #[allow(unsafe_code)] - fn deref<'a>(&'a self) -> &'a $crate::AtomicRef<'static, $T> { - static STORAGE: $crate::AtomicRef<'static, u8> = $crate::ATOMIC_U8_REF_INIT; - unsafe { $crate::core_mem::transmute(&STORAGE) } - } - } - static_atomic_ref!($($t)*); - }; - (@MAKE TY, PUB, $(#[$attr:meta])*, $N:ident) => { - #[allow(missing_copy_implementations)] - #[allow(non_camel_case_types)] - #[allow(dead_code)] - $(#[$attr])* - pub struct $N { _private: () } - #[doc(hidden)] - pub static $N: $N = $N { _private: () }; - }; - (@MAKE TY, PRIV, $(#[$attr:meta])*, $N:ident) => { - #[allow(missing_copy_implementations)] - #[allow(non_camel_case_types)] - #[allow(dead_code)] - $(#[$attr])* - struct $N { _private: () } - #[doc(hidden)] - static $N: $N = $N { _private: () }; - }; - () => (); -} - /// An internal helper function for converting `Option<&'a T>` values to /// `*mut T` for storing in the `AtomicUsize`. const fn from_opt<'a, T>(p: Option<&'a T>) -> *mut T { @@ -416,10 +333,9 @@ impl<'a, T> Default for AtomicRef<'a, T> { #[cfg(test)] mod tests { use core::sync::atomic::Ordering; + use super::AtomicRef; - static_atomic_ref! { - static FOO: AtomicRef; - } + static FOO: AtomicRef = AtomicRef::new(None); static A: i32 = 10; From 0e3e2918aedd7087c7a4904e8ebdc7aa86e32497 Mon Sep 17 00:00:00 2001 From: yvt Date: Sun, 1 Nov 2020 12:52:39 +0900 Subject: [PATCH 9/9] Remove unused reexports These reexports are no longer necessary since we removed the `static_atomic_ref` macro in 7b6f17e3. --- src/lib.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1bf940f..d11a56f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,11 +89,6 @@ pub struct AtomicRef<'a, T: 'a> { // `#![feature(const_fn)]` struct Invariant<'a, T: 'a>(&'a mut &'a mut T); -/// Re-export `core` for `static_atomic_ref!` (which may be used in a -/// non-`no_std` crate, where `core` is unavailable). -#[doc(hidden)] -pub use core::{mem as core_mem, ops as core_ops}; - /// An internal helper function for converting `Option<&'a T>` values to /// `*mut T` for storing in the `AtomicUsize`. const fn from_opt<'a, T>(p: Option<&'a T>) -> *mut T {