#![no_std]
#![deny(unconditional_recursion)]
pub mod types;
use core::cell::Cell;
use core::sync::atomic::Ordering;
#[cfg(radium_atomic_8)]
use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
#[cfg(radium_atomic_16)]
use core::sync::atomic::{AtomicI16, AtomicU16};
#[cfg(radium_atomic_32)]
use core::sync::atomic::{AtomicI32, AtomicU32};
#[cfg(radium_atomic_64)]
use core::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(radium_atomic_ptr)]
use core::sync::atomic::{AtomicIsize, AtomicPtr, AtomicUsize};
pub trait Radium<T> {
fn new(value: T) -> Self;
fn fence(order: Ordering);
fn get_mut(&mut self) -> &mut T;
fn into_inner(self) -> T;
fn load(&self, order: Ordering) -> T;
fn store(&self, value: T, order: Ordering);
fn swap(&self, value: T, order: Ordering) -> T;
fn compare_and_swap(&self, current: T, new: T, order: Ordering) -> T;
fn compare_exchange(
&self,
current: T,
new: T,
success: Ordering,
failure: Ordering,
) -> Result<T, T>;
fn compare_exchange_weak(
&self,
current: T,
new: T,
success: Ordering,
failure: Ordering,
) -> Result<T, T>;
fn fetch_and(&self, value: T, order: Ordering) -> T
where
T: marker::BitOps;
fn fetch_nand(&self, value: T, order: Ordering) -> T
where
T: marker::BitOps;
fn fetch_or(&self, value: T, order: Ordering) -> T
where
T: marker::BitOps;
fn fetch_xor(&self, value: T, order: Ordering) -> T
where
T: marker::BitOps;
fn fetch_add(&self, value: T, order: Ordering) -> T
where
T: marker::NumericOps;
fn fetch_sub(&self, value: T, order: Ordering) -> T
where
T: marker::NumericOps;
}
pub mod marker {
pub trait BitOps {}
pub trait NumericOps: BitOps {}
}
macro_rules! radium {
( 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]
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)
}
};
( 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)
}
};
( 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)
}
};
( 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)
}
};
( 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)
}
};
( 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))
}
};
( int $flag:ident $( $base:ty , $atom:ty ; )* ) => { $(
impl marker::BitOps for $base {}
impl marker::NumericOps for $base {}
#[cfg($flag)]
impl Radium<$base> for $atom {
radium!(atom $base);
radium!(atom_bit $base);
radium!(atom_int $base);
}
impl Radium<$base> for Cell<$base> {
radium!(cell $base);
radium!(cell_bit $base);
radium!(cell_int $base);
}
)* };
}
radium![int radium_atomic_8 i8, AtomicI8; u8, AtomicU8;];
radium![int radium_atomic_16 i16, AtomicI16; u16, AtomicU16;];
radium![int radium_atomic_32 i32, AtomicI32; u32, AtomicU32;];
radium![int radium_atomic_64 i64, AtomicI64; u64, AtomicU64;];
radium![int radium_atomic_ptr isize, AtomicIsize; usize, AtomicUsize;];
impl marker::BitOps for bool {}
#[cfg(radium_atomic_8)]
impl Radium<bool> for AtomicBool {
radium!(atom bool);
radium!(atom_bit bool);
#[doc(hidden)]
fn fetch_add(&self, _value: bool, _order: Ordering) -> bool {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_sub(&self, _value: bool, _order: Ordering) -> bool {
unreachable!("This method statically cannot be called")
}
}
impl Radium<bool> for Cell<bool> {
radium!(cell bool);
radium!(cell_bit bool);
#[doc(hidden)]
fn fetch_add(&self, _value: bool, _order: Ordering) -> bool {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_sub(&self, _value: bool, _order: Ordering) -> bool {
unreachable!("This method statically cannot be called")
}
}
#[cfg(radium_atomic_ptr)]
impl<T> Radium<*mut T> for AtomicPtr<T> {
radium!(atom *mut T);
#[doc(hidden)]
fn fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
}
impl<T> Radium<*mut T> for Cell<*mut T> {
radium!(cell *mut T);
#[doc(hidden)]
fn fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
#[doc(hidden)]
fn fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
#[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<bool>);
static_assertions::assert_impl_all!(Cell<i8>: Radium<i8>);
static_assertions::assert_impl_all!(Cell<u8>: Radium<u8>);
static_assertions::assert_impl_all!(Cell<i16>: Radium<i16>);
static_assertions::assert_impl_all!(Cell<u16>: Radium<u16>);
static_assertions::assert_impl_all!(Cell<i32>: Radium<i32>);
static_assertions::assert_impl_all!(Cell<u32>: Radium<u32>);
static_assertions::assert_impl_all!(Cell<i64>: Radium<i64>);
static_assertions::assert_impl_all!(Cell<u64>: Radium<u64>);
static_assertions::assert_impl_all!(Cell<isize>: Radium<isize>);
static_assertions::assert_impl_all!(Cell<usize>: Radium<usize>);
static_assertions::assert_impl_all!(Cell<*mut ()>: Radium<*mut ()>);
}
#[test]
fn always_alias() {
static_assertions::assert_impl_all!(types::RadiumBool: Radium<bool>);
static_assertions::assert_impl_all!(types::RadiumI8: Radium<i8>);
static_assertions::assert_impl_all!(types::RadiumU8: Radium<u8>);
static_assertions::assert_impl_all!(types::RadiumI16: Radium<i16>);
static_assertions::assert_impl_all!(types::RadiumU16: Radium<u16>);
static_assertions::assert_impl_all!(types::RadiumI32: Radium<i32>);
static_assertions::assert_impl_all!(types::RadiumU32: Radium<u32>);
static_assertions::assert_impl_all!(types::RadiumI64: Radium<i64>);
static_assertions::assert_impl_all!(types::RadiumU64: Radium<u64>);
static_assertions::assert_impl_all!(types::RadiumIsize: Radium<isize>);
static_assertions::assert_impl_all!(types::RadiumUsize: Radium<usize>);
static_assertions::assert_impl_all!(types::RadiumPtr<()>: Radium<*mut ()>);
}
}