#![doc = include_str!("../README.md")]
#![no_std]
#![deny(unconditional_recursion)]
pub mod marker;
pub mod portable;
pub mod types;
use core::{
cell::Cell,
sync::atomic::*,
};
use crate::marker::*;
pub use crate::types::{
Atom,
Isotope,
Radon,
};
#[doc = include_str!("../doc/radium.md")]
pub unsafe trait Radium {
type Item: Copy + PartialEq;
fn new(value: Self::Item) -> Self;
fn fence(order: Ordering);
fn get_mut(&mut self) -> &mut Self::Item;
fn into_inner(self) -> Self::Item;
fn load(&self, order: Ordering) -> Self::Item;
fn store(&self, value: Self::Item, order: Ordering);
fn swap(&self, value: Self::Item, order: Ordering) -> Self::Item;
#[deprecated = "Use `compare_exchange` or `compare_exchange_weak` instead"]
fn compare_and_swap(
&self,
current: Self::Item,
new: Self::Item,
order: Ordering,
) -> Self::Item;
fn compare_exchange(
&self,
current: Self::Item,
new: Self::Item,
success: Ordering,
failure: Ordering,
) -> Result<Self::Item, Self::Item>;
fn compare_exchange_weak(
&self,
current: Self::Item,
new: Self::Item,
success: Ordering,
failure: Ordering,
) -> Result<Self::Item, Self::Item>;
fn fetch_and(&self, value: Self::Item, order: Ordering) -> Self::Item
where Self::Item: BitOps;
fn fetch_nand(&self, value: Self::Item, order: Ordering) -> Self::Item
where Self::Item: BitOps;
fn fetch_or(&self, value: Self::Item, order: Ordering) -> Self::Item
where Self::Item: BitOps;
fn fetch_xor(&self, value: Self::Item, order: Ordering) -> Self::Item
where Self::Item: BitOps;
fn fetch_add(&self, value: Self::Item, order: Ordering) -> Self::Item
where Self::Item: NumericOps;
fn fetch_sub(&self, value: Self::Item, order: Ordering) -> Self::Item
where Self::Item: NumericOps;
fn fetch_max(&self, value: Self::Item, order: Ordering) -> Self::Item
where Self::Item: NumericOps;
fn fetch_min(&self, value: Self::Item, order: Ordering) -> Self::Item
where Self::Item: NumericOps;
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>;
}
macro_rules! radium {
($($width:literal : $bit:ident $num:ident => {
$($(@<$t:ident>)? $base:ty $(=> $atom:ident)?;)+
} )+) => { $( $(
radium!(atom $width $bit $num $(@<$t>)? $base $(=> $atom)?);
radium!(cell $width $bit $num $(@<$t>)? $base);
)+ )+ };
(atom $width:literal $bit:ident $num:ident $(@<$t:ident>)? $base:ty) => {};
(
atom $width:literal $bit:ident $num:ident
$(@<$t:ident>)? $base:ty => $atom:ident
) => {
#[cfg(target_has_atomic = $width)]
unsafe impl$(<$t>)? Radium for $atom$(<$t>)? {
type Item = $base;
#[inline]
fn new(value: $base) -> Self {
<$atom$(<$t>)?>::new(value)
}
#[inline]
fn fence(order: Ordering) {
core::sync::atomic::fence(order);
}
#[inline]
fn get_mut(&mut self) -> &mut $base {
<$atom$(<$t>)?>::get_mut(self)
}
#[inline]
fn into_inner(self) -> $base {
<$atom$(<$t>)?>::into_inner(self)
}
#[inline]
fn load(&self, order: Ordering) -> $base {
<$atom$(<$t>)?>::load(self, order)
}
#[inline]
fn store(&self, value: $base, order: Ordering) {
<$atom$(<$t>)?>::store(self, value, order);
}
#[inline]
fn swap(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::swap(self, value, order)
}
#[inline]
#[allow(deprecated)]
fn compare_and_swap(
&self,
current: $base,
new: $base,
order: Ordering,
) -> $base {
<$atom$(<$t>)?>::compare_and_swap(self, current, new, order)
}
#[inline]
fn compare_exchange(
&self,
current: $base,
new: $base,
success: Ordering,
failure: Ordering
) -> Result<$base, $base> {
<$atom$(<$t>)?>::compare_exchange(self, current, new, success, failure)
}
#[inline]
fn compare_exchange_weak(
&self,
current: $base,
new: $base,
success: Ordering,
failure: Ordering,
) -> Result<$base, $base> {
<$atom$(<$t>)?>::compare_exchange_weak(
self,
current,
new,
success,
failure,
)
}
radium!(atom $bit $(@<$t>)? $atom => $base);
radium!(atom $num $(@<$t>)? $atom => $base);
#[inline]
fn fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
func: F,
) -> Result<$base, $base>
where
F: FnMut($base) -> Option<$base>,
{
<$atom$(<$t>)?>::fetch_update(self, set_order, fetch_order, func)
}
}
};
(cell $width:literal $bit:ident $num:ident $(@<$t:ident>)? $base:ty) => {
unsafe impl$(<$t>)? Radium for Cell<$base> {
type Item = $base;
#[inline]
fn new(value: $base) -> Self {
Cell::new(value)
}
#[inline]
fn fence(_: Ordering) {}
#[inline]
fn get_mut(&mut self) -> &mut $base {
Cell::get_mut(self)
}
#[inline]
fn into_inner(self) -> $base {
Cell::into_inner(self)
}
#[inline]
fn load(&self, _: Ordering) -> $base {
Cell::get(self)
}
#[inline]
fn store(&self, value: $base, _: Ordering) {
Cell::set(self, value);
}
#[inline]
fn swap(&self, value: $base, _: Ordering) -> $base {
Cell::replace(self, value)
}
#[inline]
#[allow(deprecated)]
fn compare_and_swap(
&self,
current: $base,
new: $base,
_: Ordering,
) -> $base {
let old = Cell::get(self);
if old == current {
Cell::set(self, new);
}
old
}
#[inline]
fn compare_exchange(
&self,
current: $base,
new: $base,
_: Ordering,
_: Ordering
) -> Result<$base, $base> {
let old = Cell::get(self);
if old == current {
Cell::set(self, new);
Ok(old)
} else {
Err(old)
}
}
#[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)
}
radium!(cell $bit $(@<$t>)? $base);
radium!(cell $num $(@<$t>)? $base);
#[inline]
fn fetch_update<F>(&self, _: Ordering, _: Ordering, mut func: F)
-> Result<$base, $base>
where
F: FnMut($base) -> Option<$base>,
{
let old = Cell::get(self);
match func(old) {
Some(new) => {
Cell::set(self, new);
Ok(old)
},
None => Err(old),
}
}
}
};
(atom bit $(@<$t:ident>)? $atom:ident => $base:ty) => {
#[inline]
fn fetch_and(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_and(self, value, order)
}
#[inline]
fn fetch_nand(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_nand(self, value, order)
}
#[inline]
fn fetch_or(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_or(self, value, order)
}
#[inline]
fn fetch_xor(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_xor(self, value, order)
}
};
(atom num $(@<$t:ident>)? $atom:ident => $base:ty) => {
#[inline]
fn fetch_add(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_add(self, value, order)
}
#[inline]
fn fetch_sub(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_sub(self, value, order)
}
#[inline]
fn fetch_max(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_max(self, value, order)
}
#[inline]
fn fetch_min(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_min(self, value, order)
}
};
(cell bit $(@<$t:ident>)? $base:ty) => {
#[inline]
fn fetch_and(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, old & value);
old
}
#[inline]
fn fetch_nand(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, !(old & value));
old
}
#[inline]
fn fetch_or(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, old | value);
old
}
#[inline]
fn fetch_xor(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, old ^ value);
old
}
};
(cell num $(@<$t:ident>)? $base:ty) => {
#[inline]
fn fetch_add(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, old.wrapping_add(value));
old
}
#[inline]
fn fetch_sub(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, old.wrapping_sub(value));
old
}
#[inline]
fn fetch_max(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, core::cmp::max(old, value));
old
}
#[inline]
fn fetch_min(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, core::cmp::min(old, value));
old
}
};
(atom no_bit $(@<$t:ident>)? $atom:ident => $base:ty) => {
radium!(unreachable fetch_and, fetch_nand, fetch_or, fetch_xor);
};
(atom no_num $(@<$t:ident>)? $atom:ident => $base:ty) => {
radium!(unreachable fetch_add, fetch_sub, fetch_max, fetch_min);
};
(cell no_bit $(@<$t:ident>)? $base:ty) => {
radium!(unreachable fetch_and, fetch_nand, fetch_or, fetch_xor);
};
(cell no_num $(@<$t:ident>)? $base:ty) => {
radium!(unreachable fetch_add, fetch_sub, fetch_max, fetch_min);
};
(wrappers) => {
#[inline]
fn new(value: T) -> Self {
Self {
inner: Radium::new(value),
}
}
#[inline]
fn get_mut(&mut self) -> &mut T {
Radium::get_mut(&mut self.inner)
}
#[inline]
fn into_inner(self) -> T {
Radium::into_inner(self.inner)
}
#[inline]
fn load(&self, order: Ordering) -> T {
Radium::load(&self.inner, order)
}
#[inline]
fn store(&self, value: T, order: Ordering) {
Radium::store(&self.inner, value, order);
}
#[inline]
fn swap(&self, value: T, order: Ordering) -> T {
Radium::swap(&self.inner, value, order)
}
#[inline]
#[allow(deprecated)]
fn compare_and_swap(
&self,
current: T,
new: T,
order: Ordering,
) -> T {
Radium::compare_and_swap(&self.inner, current, new, order)
}
#[inline]
fn compare_exchange(
&self,
current: T,
new: T,
success: Ordering,
failure: Ordering,
) -> Result<T, T> {
Radium::compare_exchange(
&self.inner,
current,
new,
success,
failure,
)
}
#[inline]
fn compare_exchange_weak(
&self,
current: T,
new: T,
success: Ordering,
failure: Ordering,
) -> Result<T, T> {
Radium::compare_exchange_weak(
&self.inner,
current,
new,
success,
failure,
)
}
#[inline]
fn fetch_and(&self, value: T, order: Ordering) -> T
where
T: BitOps,
{
Radium::fetch_and(&self.inner, value, order)
}
#[inline]
fn fetch_nand(&self, value: T, order: Ordering) -> T
where
T: BitOps,
{
Radium::fetch_nand(&self.inner, value, order)
}
#[inline]
fn fetch_or(&self, value: T, order: Ordering) -> T
where
T: BitOps,
{
Radium::fetch_or(&self.inner, value, order)
}
#[inline]
fn fetch_xor(&self, value: T, order: Ordering) -> T
where
T: BitOps,
{
Radium::fetch_xor(&self.inner, value, order)
}
#[inline]
fn fetch_add(&self, value: T, order: Ordering) -> T
where
T: NumericOps,
{
Radium::fetch_add(&self.inner, value, order)
}
#[inline]
fn fetch_sub(&self, value: T, order: Ordering) -> T
where
T: NumericOps,
{
Radium::fetch_sub(&self.inner, value, order)
}
#[inline]
fn fetch_max(&self, value: T, order: Ordering) -> T
where
T: NumericOps,
{
Radium::fetch_max(&self.inner, value, order)
}
#[inline]
fn fetch_min(&self, value: T, order: Ordering) -> T
where
T: NumericOps,
{
Radium::fetch_min(&self.inner, value, order)
}
#[inline]
fn fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
func: F,
) -> Result<T, T>
where
F: FnMut(T) -> Option<T>,
{
Radium::fetch_update(&self.inner, set_order, fetch_order, func)
}
};
(unreachable $($n:ident),+ $(,)?) => { $(
fn $n(&self, _: Self::Item, _: Ordering) -> Self::Item {
unreachable!(
"This function is statically guaranteed to never be callable",
);
}
)+ };
}
radium! {
"8": bit no_num => {
bool => AtomicBool;
}
"8": bit num => {
i8 => AtomicI8;
u8 => AtomicU8;
}
"16": bit num => {
i16 => AtomicI16;
u16 => AtomicU16;
}
"32": bit num => {
i32 => AtomicI32;
u32 => AtomicU32;
}
"64": bit num => {
i64 => AtomicI64;
u64 => AtomicU64;
}
"128": bit num => {
i128; u128; }
"ptr": bit num => {
isize => AtomicIsize;
usize => AtomicUsize;
}
"ptr": no_bit no_num => {
@<T> *mut T => AtomicPtr;
}
}
unsafe impl<T> Radium for Atom<T>
where
T: Atomic + PartialEq,
T::Atom: Radium<Item = T>,
{
type Item = T;
radium!(wrappers);
fn fence(order: Ordering) {
core::sync::atomic::fence(order);
}
}
unsafe impl<T> Radium for Isotope<T>
where
T: Nuclear + PartialEq,
T::Nucleus: Radium<Item = T>,
{
type Item = T;
radium!(wrappers);
fn fence(order: Ordering) {
<T::Nucleus as Radium>::fence(order);
}
}
unsafe impl<T> Radium for Radon<T>
where
T: Nuclear + PartialEq,
Cell<T>: Radium<Item = T>,
{
type Item = T;
radium!(wrappers);
fn fence(_: Ordering) {
}
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use core::sync::atomic::*;
use static_assertions::*;
use super::*;
use crate::types::*;
#[test]
fn absent_traits() {
assert_not_impl_any!(bool: NumericOps);
assert_not_impl_any!(*mut u8: BitOps, NumericOps);
}
#[test]
fn present_traits() {
assert_impl_all!(bool: BitOps);
assert_impl_all!(usize: BitOps, NumericOps);
}
#[test]
fn always_cell() {
assert_impl_all!(Cell<bool>: Radium<Item = bool>);
assert_impl_all!(Cell<i8>: Radium<Item = i8>);
assert_impl_all!(Cell<u8>: Radium<Item = u8>);
assert_impl_all!(Cell<i16>: Radium<Item = i16>);
assert_impl_all!(Cell<u16>: Radium<Item = u16>);
assert_impl_all!(Cell<i32>: Radium<Item = i32>);
assert_impl_all!(Cell<u32>: Radium<Item = u32>);
assert_impl_all!(Cell<i64>: Radium<Item = i64>);
assert_impl_all!(Cell<u64>: Radium<Item = u64>);
assert_impl_all!(Cell<isize>: Radium<Item = isize>);
assert_impl_all!(Cell<usize>: Radium<Item = usize>);
assert_impl_all!(Cell<*mut ()>: Radium<Item = *mut ()>);
}
#[test]
fn always_alias() {
assert_impl_all!(RadiumBool: Radium<Item = bool>);
assert_impl_all!(RadiumI8: Radium<Item = i8>);
assert_impl_all!(RadiumU8: Radium<Item = u8>);
assert_impl_all!(RadiumI16: Radium<Item = i16>);
assert_impl_all!(RadiumU16: Radium<Item = u16>);
assert_impl_all!(RadiumI32: Radium<Item = i32>);
assert_impl_all!(RadiumU32: Radium<Item = u32>);
assert_impl_all!(RadiumI64: Radium<Item = i64>);
assert_impl_all!(RadiumU64: Radium<Item = u64>);
assert_impl_all!(RadiumIsize: Radium<Item = isize>);
assert_impl_all!(RadiumUsize: Radium<Item = usize>);
assert_impl_all!(RadiumPtr<()>: Radium<Item = *mut ()>);
assert_impl_all!(Isotope<bool>: Radium<Item = bool>);
assert_impl_all!(Isotope<i8>: Radium<Item = i8>);
assert_impl_all!(Isotope<u8>: Radium<Item = u8>);
assert_impl_all!(Isotope<i16>: Radium<Item = i16>);
assert_impl_all!(Isotope<u16>: Radium<Item = u16>);
assert_impl_all!(Isotope<i32>: Radium<Item = i32>);
assert_impl_all!(Isotope<u32>: Radium<Item = u32>);
assert_impl_all!(Isotope<i64>: Radium<Item = i64>);
assert_impl_all!(Isotope<u64>: Radium<Item = u64>);
assert_impl_all!(Isotope<isize>: Radium<Item = isize>);
assert_impl_all!(Isotope<usize>: Radium<Item = usize>);
assert_impl_all!(Isotope<*mut ()>: Radium<Item = *mut ()>);
}
#[test]
fn maybe_atom() {
#[cfg(target_has_atomic = "8")]
{
assert_impl_all!(AtomicBool: Radium<Item = bool>);
assert_impl_all!(AtomicI8: Radium<Item = i8>);
assert_impl_all!(AtomicU8: Radium<Item = u8>);
assert_impl_all!(Atom<bool>: Radium<Item = bool>);
assert_impl_all!(Atom<i8>: Radium<Item = i8>);
assert_impl_all!(Atom<u8>: Radium<Item = u8>);
}
#[cfg(target_has_atomic = "16")]
{
assert_impl_all!(AtomicI16: Radium<Item = i16>);
assert_impl_all!(AtomicU16: Radium<Item = u16>);
assert_impl_all!(Atom<i16>: Radium<Item = i16>);
assert_impl_all!(Atom<u16>: Radium<Item = u16>);
}
#[cfg(target_has_atomic = "32")]
{
assert_impl_all!(AtomicI32: Radium<Item = i32>);
assert_impl_all!(AtomicU32: Radium<Item = u32>);
assert_impl_all!(Atom<i32>: Radium<Item = i32>);
assert_impl_all!(Atom<u32>: Radium<Item = u32>);
}
#[cfg(target_has_atomic = "64")]
{
assert_impl_all!(AtomicI64: Radium<Item = i64>);
assert_impl_all!(AtomicU64: Radium<Item = u64>);
assert_impl_all!(Atom<i64>: Radium<Item = i64>);
assert_impl_all!(Atom<u64>: Radium<Item = u64>);
}
#[cfg(target_has_atomic = "ptr")]
{
assert_impl_all!(AtomicIsize: Radium<Item = isize>);
assert_impl_all!(AtomicUsize: Radium<Item = usize>);
assert_impl_all!(AtomicPtr<()>: Radium<Item = *mut ()>);
assert_impl_all!(Atom<isize>: Radium<Item = isize>);
assert_impl_all!(Atom<usize>: Radium<Item = usize>);
assert_impl_all!(Atom<*mut ()>: Radium<Item = *mut ()>);
}
}
}