--- /dev/null
+//! `radium` provides a series of helpers for a uniform API over both atomic
+//! types like [`AtomicUsize`], and non-atomic types like [`Cell<T>`].
+//!
+//! This crate is `#![no_std]`-compatible, and uses no non-core types.
+//!
+//! For details, see the documentation for [`Radium`].
+//!
+//! The `types` module provides type names that are atomic where the target
+//! supports it, and fall back to `Cell` when the target does not.
+//!
+//! The `if_atomic!` macro provides a means of conditional compilation based on
+//! the presence of atomic instructions. It is a substitute for the
+//! `cfg(target_has_atomic)` or `cfg(accessible)` attribute tests, which are not
+//! yet stabilized.
+//!
+//! ---
+//!
+//! **@kneecaw** - <https://twitter.com/kneecaw/status/1132695060812849154>
+//! > Feelin' lazy: Has someone already written a helper trait abstracting
+//! > operations over `AtomicUsize` and `Cell<usize>` for generic code which may
+//! > not care about atomicity?
+//!
+//! **@ManishEarth** - <https://twitter.com/ManishEarth/status/1132706585300496384>
+//! > no but call the crate radium
+//! >
+//! > (since people didn't care that it was radioactive and used it in everything)
+//!
+//! [`AtomicUsize`]: core::sync::atomic::AtomicUsize
+//! [`Cell<T>`]: core::cell::Cell
+
+#![no_std]
+#![deny(unconditional_recursion)]
+
+#[macro_use]
+mod macros;
+
+pub mod types;
+
+use core::cell::Cell;
+use core::sync::atomic::Ordering;
+
+if_atomic! {
+ if atomic(8) {
+ use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
+ }
+ if atomic(16) {
+ use core::sync::atomic::{AtomicI16, AtomicU16};
+ }
+ if atomic(32) {
+ use core::sync::atomic::{AtomicI32, AtomicU32};
+ }
+ if atomic(64) {
+ use core::sync::atomic::{AtomicI64, AtomicU64};
+ }
+ if atomic(ptr) {
+ use core::sync::atomic::{AtomicIsize, AtomicPtr, AtomicUsize};
+ }
+}
+
+/// A maybe-atomic shared mutable fundamental type `T`.
+///
+/// This trait is implemented by both the [atomic wrapper] type for `T`, and by
+/// [`Cell<T>`], providing a consistent interface for interacting with the two
+/// types.
+///
+/// This trait provides methods predicated on marker traits for the underlying
+/// fundamental. Only types which can be viewed as sequences of bits may use the
+/// functions for bit-wise arithmetic, and only types which can be used as
+/// integers may use the functions for numeric arithmetic. Use of these methods
+/// on insufficient underlying types (for example, `Radium::fetch_and` on an
+/// atomic or cell-wrapped pointer) will cause a compiler error.
+///
+/// [atomic wrapper]: core::sync::atomic
+/// [`Cell<T>`]: core::cell::Cell
+pub trait Radium {
+ type Item;
+ /// Creates a new value of this type.
+ fn new(value: Self::Item) -> Self;
+
+ /// If the underlying value is atomic, calls [`fence`] with the given
+ /// [`Ordering`]. Otherwise, does nothing.
+ ///
+ /// [`Ordering`]: core::sync::atomic::Ordering
+ /// [`fence`]: core::sync::atomic::fence
+ fn fence(order: Ordering);
+
+ /// Returns a mutable reference to the underlying value.
+ ///
+ /// This is safe because the mutable reference to `self` guarantees that no
+ /// other references exist to this value.
+ fn get_mut(&mut self) -> &mut Self::Item;
+
+ /// Consumes the wrapper and returns the contained value.
+ ///
+ /// This is safe as passing by value ensures no other references exist.
+ fn into_inner(self) -> Self::Item;
+
+ /// Load a value from this object.
+ ///
+ /// Ordering values are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::load`].
+ ///
+ /// [`AtomicUsize::load`]: core::sync::atomic::AtomicUsize::load
+ fn load(&self, order: Ordering) -> Self::Item;
+
+ /// Store a value in this object.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::store`].
+ ///
+ /// [`AtomicUsize::store`]: core::sync::atomic::AtomicUsize::store
+ fn store(&self, value: Self::Item, order: Ordering);
+
+ /// Swap with the value stored in this object.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::swap`].
+ ///
+ /// [`AtomicUsize::swap`]: core::sync::atomic::AtomicUsize::swap
+ fn swap(&self, value: Self::Item, order: Ordering) -> Self::Item;
+
+ /// Stores a value into this object if the currently-stored value is the
+ /// same as the `current` value.
+ ///
+ /// The return value is always the previously-stored value. If it is equal to
+ /// `current`, then the value was updated with `new`.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::compare_and_swap`].
+ ///
+ /// [`AtomicUsize::compare_and_swap`]: core::sync::atomic::AtomicUsize::compare_and_swap
+ #[deprecated = "Use `compare_exchange` or `compare_exchange_weak` instead"]
+ fn compare_and_swap(&self, current: Self::Item, new: Self::Item, order: Ordering)
+ -> Self::Item;
+
+ /// Stores a value into this object if the currently-stored value is the
+ /// same as the `current` value.
+ ///
+ /// The return value is a `Result` indicating whether the new value was
+ /// written, and containing the previously-stored value. On success, this
+ /// value is guaranteed to be equal to `current`.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::compare_exchange`].
+ ///
+ /// [`AtomicUsize::compare_exchange`]: core::sync::atomic::AtomicUsize::compare_exchange
+ fn compare_exchange(
+ &self,
+ current: Self::Item,
+ new: Self::Item,
+ success: Ordering,
+ failure: Ordering,
+ ) -> Result<Self::Item, Self::Item>;
+
+ /// Stores a value into this object if the currently-stored value is the
+ /// same as the `current` value.
+ ///
+ /// Unlike `compare_exchange`, this function is allowed to spuriously fail
+ /// even when the comparison succeeds, which can result in more efficient
+ /// code on some platforms. The return value is a `Result` indicating
+ /// whether the new value was written, and containing the previously-stored
+ /// value.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::compare_exchange_weak`].
+ ///
+ /// [`AtomicUsize::compare_exchange_weak`]: core::sync::atomic::AtomicUsize::compare_exchange_weak
+ fn compare_exchange_weak(
+ &self,
+ current: Self::Item,
+ new: Self::Item,
+ success: Ordering,
+ failure: Ordering,
+ ) -> Result<Self::Item, Self::Item>;
+
+ /// Performs a bitwise "and" on the currently-stored value and the argument
+ /// `value`, and stores the result in `self`.
+ ///
+ /// Returns the previously-stored value.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::fetch_and`].
+ ///
+ /// [`AtomicUsize::fetch_and`]: core::sync::atomic::AtomicUsize::fetch_and
+ fn fetch_and(&self, value: Self::Item, order: Ordering) -> Self::Item
+ where
+ Self::Item: marker::BitOps;
+
+ /// Performs a bitwise "nand" on the currently-stored value and the argument
+ /// `value`, and stores the result in `self`.
+ ///
+ /// Returns the previously-stored value.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::fetch_nand`].
+ ///
+ /// [`AtomicUsize::fetch_nand`]: core::sync::atomic::AtomicUsize::fetch_nand
+ fn fetch_nand(&self, value: Self::Item, order: Ordering) -> Self::Item
+ where
+ Self::Item: marker::BitOps;
+
+ /// Performs a bitwise "or" on the currently-stored value and the argument
+ /// `value`, and stores the result in `self`.
+ ///
+ /// Returns the previously-stored value.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::fetch_or`].
+ ///
+ /// [`AtomicUsize::fetch_or`]: core::sync::atomic::AtomicUsize::fetch_or
+ fn fetch_or(&self, value: Self::Item, order: Ordering) -> Self::Item
+ where
+ Self::Item: marker::BitOps;
+
+ /// Performs a bitwise "xor" on the currently-stored value and the argument
+ /// `value`, and stores the result in `self`.
+ ///
+ /// Returns the previously-stored value.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::fetch_xor`].
+ ///
+ /// [`AtomicUsize::fetch_xor`]: core::sync::atomic::AtomicUsize::fetch_xor
+ fn fetch_xor(&self, value: Self::Item, order: Ordering) -> Self::Item
+ where
+ Self::Item: marker::BitOps;
+
+ /// Adds `value` to the currently-stored value, wrapping on overflow, and
+ /// stores the result in `self`.
+ ///
+ /// Returns the previously-stored value.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::fetch_add`].
+ ///
+ /// [`AtomicUsize::fetch_add`]: core::sync::atomic::AtomicUsize::fetch_add
+ fn fetch_add(&self, value: Self::Item, order: Ordering) -> Self::Item
+ where
+ Self::Item: marker::NumericOps;
+
+ /// Subtracts `value` from the currently-stored value, wrapping on
+ /// underflow, and stores the result in `self`.
+ ///
+ /// Returns the previously-stored value.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::fetch_sub`].
+ ///
+ /// [`AtomicUsize::fetch_sub`]: core::sync::atomic::AtomicUsize::fetch_sub
+ fn fetch_sub(&self, value: Self::Item, order: Ordering) -> Self::Item
+ where
+ Self::Item: marker::NumericOps;
+
+ /// Fetches the value, and applies a function to it that returns an
+ /// optional new value.
+ ///
+ /// Note: This may call the function multiple times if the value has been
+ /// changed from other threads in the meantime, as long as the function
+ /// returns `Some(_)`, but the function will have been applied only once to
+ /// the stored value.
+ ///
+ /// Returns a `Result` of `Ok(previous_value)` if the function returned
+ /// `Some(_)`, else `Err(previous_value)`.
+ ///
+ /// Ordering arguments are ignored by non-atomic types.
+ ///
+ /// See also: [`AtomicUsize::fetch_update`].
+ ///
+ /// [`AtomicUsize::fetch_update`]: core::sync::atomic::AtomicUsize::fetch_update
+ fn fetch_update<F>(
+ &self,
+ set_order: Ordering,
+ fetch_order: Ordering,
+ f: F,
+ ) -> Result<Self::Item, Self::Item>
+ where
+ F: FnMut(Self::Item) -> Option<Self::Item>;
+}
+
+/// Marker traits used by [`Radium`].
+pub mod marker {
+ /// Types supporting maybe-atomic bitwise operations.
+ ///
+ /// Types implementing this trait support the [`fetch_and`], [`fetch_nand`],
+ /// [`fetch_or`], and [`fetch_xor`] maybe-atomic operations.
+ ///
+ /// [`fetch_and`]: crate::Radium::fetch_and
+ /// [`fetch_nand`]: crate::Radium::fetch_nand
+ /// [`fetch_or`]: crate::Radium::fetch_or
+ /// [`fetch_xor`]: crate::Radium::fetch_xor
+ ///
+ /// `bool` and all integer fundamental types implement this.
+ ///
+ /// ```rust
+ /// # use core::sync::atomic::*;
+ /// # use radium::Radium;
+ /// let num: AtomicUsize = AtomicUsize::new(0);
+ /// Radium::fetch_or(&num, 2, Ordering::Relaxed);
+ /// ```
+ ///
+ /// Pointers do not. This will cause a compiler error.
+ ///
+ /// ```rust,compile_fail
+ /// # use core::sync::atomic::*;
+ /// # use radium::Radium;
+ /// # use core::ptr;
+ /// let ptr: AtomicPtr<usize> = Default::default();
+ /// Radium::fetch_or(&ptr, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ pub trait BitOps {}
+
+ /// Types supporting maybe-atomic arithmetic operations.
+ ///
+ /// Types implementing this trait support the [`fetch_add`] and
+ /// [`fetch_sub`] maybe-atomic operations.
+ ///
+ /// [`fetch_add`]: crate::Radium::fetch_add
+ /// [`fetch_sub`]: crate::Radium::fetch_sub
+ ///
+ /// The integer types, such as `usize` and `i32`, implement this trait.
+ ///
+ /// ```rust
+ /// # use core::sync::atomic::*;
+ /// # use radium::Radium;
+ /// let num: AtomicUsize = AtomicUsize::new(2);
+ /// Radium::fetch_add(&num, 2, Ordering::Relaxed);
+ /// ```
+ ///
+ /// `bool` and pointers do not. This will cause a compiler error.
+ ///
+ /// ```rust,compile_fail
+ /// # use core::sync::atomic::*;
+ /// # use radium::Radium;
+ /// let bit: AtomicBool = AtomicBool::new(false);
+ /// Radium::fetch_add(&bit, true, Ordering::Relaxed);
+ /// ```
+ pub trait NumericOps: BitOps {}
+}
+
+macro_rules! radium {
+ // Emit the universal `Radium` trait function bodies for atomic types.
+ ( atom $base:ty ) => {
+ #[inline]
+ fn new(value: $base) -> Self {
+ Self::new(value)
+ }
+
+ #[inline]
+ fn fence(order: Ordering) {
+ core::sync::atomic::fence(order);
+ }
+
+ #[inline]
+ fn get_mut(&mut self) -> &mut $base {
+ self.get_mut()
+ }
+
+ #[inline]
+ fn into_inner(self) -> $base {
+ self.into_inner()
+ }
+
+ #[inline]
+ fn load(&self, order: Ordering) -> $base {
+ self.load(order)
+ }
+
+ #[inline]
+ fn store(&self, value: $base, order: Ordering) {
+ self.store(value, order);
+ }
+
+ #[inline]
+ fn swap(&self, value: $base, order: Ordering) -> $base {
+ self.swap(value, order)
+ }
+
+ #[inline]
+ #[allow(deprecated)]
+ fn compare_and_swap(&self, current: $base, new: $base, order: Ordering) -> $base {
+ self.compare_and_swap(current, new, order)
+ }
+
+ #[inline]
+ fn compare_exchange(
+ &self,
+ current: $base,
+ new: $base,
+ success: Ordering,
+ failure: Ordering,
+ ) -> Result<$base, $base> {
+ self.compare_exchange(current, new, success, failure)
+ }
+
+ #[inline]
+ fn compare_exchange_weak(
+ &self,
+ current: $base,
+ new: $base,
+ success: Ordering,
+ failure: Ordering,
+ ) -> Result<$base, $base> {
+ self.compare_exchange_weak(current, new, success, failure)
+ }
+
+ #[inline]
+ fn fetch_update<F>(
+ &self,
+ set_order: Ordering,
+ fetch_order: Ordering,
+ f: F,
+ ) -> Result<$base, $base>
+ where
+ F: FnMut($base) -> Option<$base>,
+ {
+ self.fetch_update(set_order, fetch_order, f)
+ }
+ };
+
+ // Emit the `Radium` trait function bodies for bit-wise types.
+ ( atom_bit $base:ty ) => {
+ #[inline]
+ fn fetch_and(&self, value: $base, order: Ordering) -> $base {
+ self.fetch_and(value, order)
+ }
+
+ #[inline]
+ fn fetch_nand(&self, value: $base, order: Ordering) -> $base {
+ self.fetch_nand(value, order)
+ }
+
+ #[inline]
+ fn fetch_or(&self, value: $base, order: Ordering) -> $base {
+ self.fetch_or(value, order)
+ }
+
+ #[inline]
+ fn fetch_xor(&self, value: $base, order: Ordering) -> $base {
+ self.fetch_xor(value, order)
+ }
+ };
+
+ // Emit the `Radium` trait function bodies for integral types.
+ ( atom_int $base:ty ) => {
+ #[inline]
+ fn fetch_add(&self, value: $base, order: Ordering) -> $base {
+ self.fetch_add(value, order)
+ }
+
+ #[inline]
+ fn fetch_sub(&self, value: $base, order: Ordering) -> $base {
+ self.fetch_sub(value, order)
+ }
+ };
+
+ // Emit the universal `Radium` trait function bodies for `Cell<_>`.
+ ( cell $base:ty ) => {
+ #[inline]
+ fn new(value: $base) -> Self {
+ Cell::new(value)
+ }
+
+ #[inline]
+ fn fence(_: Ordering) {}
+
+ #[inline]
+ fn get_mut(&mut self) -> &mut $base {
+ self.get_mut()
+ }
+
+ #[inline]
+ fn into_inner(self) -> $base {
+ self.into_inner()
+ }
+
+ #[inline]
+ fn load(&self, _: Ordering) -> $base {
+ self.get()
+ }
+
+ #[inline]
+ fn store(&self, value: $base, _: Ordering) {
+ self.set(value);
+ }
+
+ #[inline]
+ fn swap(&self, value: $base, _: Ordering) -> $base {
+ self.replace(value)
+ }
+
+ #[inline]
+ fn compare_and_swap(&self, current: $base, new: $base, _: Ordering) -> $base {
+ if self.get() == current {
+ self.replace(new)
+ } else {
+ self.get()
+ }
+ }
+
+ #[inline]
+ fn compare_exchange(
+ &self,
+ current: $base,
+ new: $base,
+ _: Ordering,
+ _: Ordering,
+ ) -> Result<$base, $base> {
+ if self.get() == current {
+ Ok(self.replace(new))
+ } else {
+ Err(self.get())
+ }
+ }
+
+ #[inline]
+ fn compare_exchange_weak(
+ &self,
+ current: $base,
+ new: $base,
+ success: Ordering,
+ failure: Ordering,
+ ) -> Result<$base, $base> {
+ Radium::compare_exchange(self, current, new, success, failure)
+ }
+
+ #[inline]
+ fn fetch_update<F>(&self, _: Ordering, _: Ordering, mut f: F) -> Result<$base, $base>
+ where
+ F: FnMut($base) -> Option<$base>,
+ {
+ match f(self.get()) {
+ Some(x) => Ok(self.replace(x)),
+ None => Err(self.get()),
+ }
+ }
+ };
+
+ // Emit the `Radium` trait function bodies for bit-wise types.
+ ( cell_bit $base:ty ) => {
+ #[inline]
+ fn fetch_and(&self, value: $base, _: Ordering) -> $base {
+ self.replace(self.get() & value)
+ }
+
+ #[inline]
+ fn fetch_nand(&self, value: $base, _: Ordering) -> $base {
+ self.replace(!(self.get() & value))
+ }
+
+ #[inline]
+ fn fetch_or(&self, value: $base, _: Ordering) -> $base {
+ self.replace(self.get() | value)
+ }
+
+ #[inline]
+ fn fetch_xor(&self, value: $base, _: Ordering) -> $base {
+ self.replace(self.get() ^ value)
+ }
+ };
+
+ // Emit the `Radium` trait function bodies for integral types.
+ ( cell_int $base:ty ) => {
+ #[inline]
+ fn fetch_add(&self, value: $base, _: Ordering) -> $base {
+ self.replace(self.get().wrapping_add(value))
+ }
+
+ #[inline]
+ fn fetch_sub(&self, value: $base, _: Ordering) -> $base {
+ self.replace(self.get().wrapping_sub(value))
+ }
+ };
+}
+
+macro_rules! radium_int {
+ ( $( $width:tt: $base:ty , $atom:ty ; )* ) => { $(
+ impl marker::BitOps for $base {}
+ impl marker::NumericOps for $base {}
+
+ if_atomic!(if atomic($width) {
+ impl Radium for $atom {
+ type Item = $base;
+
+ radium!(atom $base);
+ radium!(atom_bit $base);
+ radium!(atom_int $base);
+ }
+ });
+
+ impl Radium for Cell<$base> {
+ type Item = $base;
+
+ radium!(cell $base);
+ radium!(cell_bit $base);
+ radium!(cell_int $base);
+ }
+ )* };
+}
+
+radium_int! {
+ 8: i8, AtomicI8;
+ 8: u8, AtomicU8;
+ 16: i16, AtomicI16;
+ 16: u16, AtomicU16;
+ 32: i32, AtomicI32;
+ 32: u32, AtomicU32;
+ 64: i64, AtomicI64;
+ 64: u64, AtomicU64;
+ size: isize, AtomicIsize;
+ size: usize, AtomicUsize;
+}
+
+impl marker::BitOps for bool {}
+
+if_atomic!(if atomic(bool) {
+ impl Radium for AtomicBool {
+ type Item = bool;
+
+ radium!(atom bool);
+ radium!(atom_bit bool);
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let atom = AtomicBool::new(false);
+ /// Radium::fetch_add(&atom, true, Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_add(&self, _value: bool, _order: Ordering) -> bool {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let atom = AtomicBool::new(false);
+ /// Radium::fetch_sub(&atom, true, Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_sub(&self, _value: bool, _order: Ordering) -> bool {
+ unreachable!("This method statically cannot be called")
+ }
+ }
+});
+
+impl Radium for Cell<bool> {
+ type Item = bool;
+
+ radium!(cell bool);
+ radium!(cell_bit bool);
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let cell = Cell::<bool>::new(false);
+ /// Radium::fetch_add(&cell, true, Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_add(&self, _value: bool, _order: Ordering) -> bool {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let cell = Cell::<bool>::new(false);
+ /// Radium::fetch_sub(&cell, true, Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_sub(&self, _value: bool, _order: Ordering) -> bool {
+ unreachable!("This method statically cannot be called")
+ }
+}
+
+if_atomic!(if atomic(ptr) {
+ impl<T> Radium for AtomicPtr<T> {
+ type Item = *mut T;
+
+ radium!(atom *mut T);
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
+ /// Radium::fetch_and(&atom, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
+ /// Radium::fetch_nand(&atom, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
+ /// Radium::fetch_or(&atom, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
+ /// Radium::fetch_xor(&atom, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
+ /// Radium::fetch_add(&atom, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
+ /// Radium::fetch_sub(&atom, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+ }
+});
+
+impl<T> Radium for Cell<*mut T> {
+ type Item = *mut T;
+
+ radium!(cell *mut T);
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
+ /// Radium::fetch_and(&cell, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
+ /// Radium::fetch_nand(&cell, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
+ /// Radium::fetch_or(&cell, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
+ /// Radium::fetch_xor(&cell, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
+ /// Radium::fetch_add(&cell, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+
+ /// ```compile_fail
+ /// # use std::{ptr, sync::atomic::*, cell::*};
+ /// # use radium::*;
+ /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
+ /// Radium::fetch_sub(&cell, ptr::null_mut(), Ordering::Relaxed);
+ /// ```
+ #[doc(hidden)]
+ fn fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T {
+ unreachable!("This method statically cannot be called")
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use core::cell::Cell;
+
+ #[test]
+ fn absent_traits() {
+ static_assertions::assert_not_impl_any!(bool: marker::NumericOps);
+ static_assertions::assert_not_impl_any!(*mut u8: marker::BitOps, marker::NumericOps);
+ }
+
+ #[test]
+ fn present_traits() {
+ static_assertions::assert_impl_all!(bool: marker::BitOps);
+ static_assertions::assert_impl_all!(usize: marker::BitOps, marker::NumericOps);
+ }
+
+ #[test]
+ fn always_cell() {
+ static_assertions::assert_impl_all!(Cell<bool>: Radium<Item = bool>);
+ static_assertions::assert_impl_all!(Cell<i8>: Radium<Item = i8>);
+ static_assertions::assert_impl_all!(Cell<u8>: Radium<Item = u8>);
+ static_assertions::assert_impl_all!(Cell<i16>: Radium<Item = i16>);
+ static_assertions::assert_impl_all!(Cell<u16>: Radium<Item = u16>);
+ static_assertions::assert_impl_all!(Cell<i32>: Radium<Item = i32>);
+ static_assertions::assert_impl_all!(Cell<u32>: Radium<Item = u32>);
+ static_assertions::assert_impl_all!(Cell<i64>: Radium<Item = i64>);
+ static_assertions::assert_impl_all!(Cell<u64>: Radium<Item = u64>);
+ static_assertions::assert_impl_all!(Cell<isize>: Radium<Item = isize>);
+ static_assertions::assert_impl_all!(Cell<usize>: Radium<Item = usize>);
+ static_assertions::assert_impl_all!(Cell<*mut ()>: Radium<Item = *mut ()>);
+ }
+
+ #[test]
+ fn always_alias() {
+ static_assertions::assert_impl_all!(types::RadiumBool: Radium<Item = bool>);
+ static_assertions::assert_impl_all!(types::RadiumI8: Radium<Item = i8>);
+ static_assertions::assert_impl_all!(types::RadiumU8: Radium<Item = u8>);
+ static_assertions::assert_impl_all!(types::RadiumI16: Radium<Item = i16>);
+ static_assertions::assert_impl_all!(types::RadiumU16: Radium<Item = u16>);
+ static_assertions::assert_impl_all!(types::RadiumI32: Radium<Item = i32>);
+ static_assertions::assert_impl_all!(types::RadiumU32: Radium<Item = u32>);
+ static_assertions::assert_impl_all!(types::RadiumI64: Radium<Item = i64>);
+ static_assertions::assert_impl_all!(types::RadiumU64: Radium<Item = u64>);
+ static_assertions::assert_impl_all!(types::RadiumIsize: Radium<Item = isize>);
+ static_assertions::assert_impl_all!(types::RadiumUsize: Radium<Item = usize>);
+ static_assertions::assert_impl_all!(types::RadiumPtr<()>: Radium<Item = *mut ()>);
+ }
+
+ #[test]
+ fn maybe_atom() {
+ if_atomic! {
+ if atomic(bool) {
+ use core::sync::atomic::*;
+ static_assertions::assert_impl_all!(AtomicBool: Radium<Item = bool>);
+ }
+ if atomic(8) {
+ static_assertions::assert_impl_all!(AtomicI8: Radium<Item = i8>);
+ static_assertions::assert_impl_all!(AtomicU8: Radium<Item = u8>);
+ }
+ if atomic(16) {
+ static_assertions::assert_impl_all!(AtomicI16: Radium<Item = i16>);
+ static_assertions::assert_impl_all!(AtomicU16: Radium<Item = u16>);
+ }
+ if atomic(32) {
+ static_assertions::assert_impl_all!(AtomicI32: Radium<Item = i32>);
+ static_assertions::assert_impl_all!(AtomicU32: Radium<Item = u32>);
+ }
+ if atomic(64) {
+ static_assertions::assert_impl_all!(AtomicI64: Radium<Item = i64>);
+ static_assertions::assert_impl_all!(AtomicU64: Radium<Item = u64>);
+ }
+ if atomic(size) {
+ static_assertions::assert_impl_all!(AtomicIsize: Radium<Item = isize>);
+ static_assertions::assert_impl_all!(AtomicUsize: Radium<Item = usize>);
+ }
+ if atomic(ptr) {
+ static_assertions::assert_impl_all!(AtomicPtr<()>: Radium<Item = *mut ()>);
+ }
+ }
+ }
+}