#![doc = include_str!("../doc/types.md")]
#[allow(unused_imports)]
use core::{
cell::Cell,
fmt::{
self,
Debug,
Formatter,
},
sync::atomic::Ordering,
};
use crate::{
marker::{
Atomic,
Nuclear,
},
Radium,
};
#[repr(transparent)]
#[doc = include_str!("../doc/atom.md")]
pub struct Atom<T>
where
T: Atomic,
T::Atom: Radium<Item = T>,
{
pub(crate) inner: T::Atom,
}
impl<T> Debug for Atom<T>
where
T: Atomic + Debug,
T::Atom: Radium<Item = T> + Debug,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
Debug::fmt(&self.inner, fmt)
}
}
impl<T> Default for Atom<T>
where
T: Atomic + Default,
T::Atom: Radium<Item = T> + Default,
{
#[inline]
fn default() -> Self {
Self {
inner: Default::default(),
}
}
}
impl<T> From<T> for Atom<T>
where
T: Atomic,
T::Atom: Radium<Item = T> + From<T>,
{
#[inline]
fn from(val: T) -> Self {
Self {
inner: From::from(val),
}
}
}
#[repr(transparent)]
#[doc = include_str!("../doc/isotope.md")]
pub struct Isotope<T>
where
T: Nuclear,
T::Nucleus: Radium<Item = T>,
{
pub(crate) inner: T::Nucleus,
}
impl<T> Debug for Isotope<T>
where
T: Nuclear + Debug,
T::Nucleus: Radium<Item = T> + Debug,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
Debug::fmt(&self.inner, fmt)
}
}
impl<T> Default for Isotope<T>
where
T: Nuclear + Default,
T::Nucleus: Radium<Item = T> + Default,
{
#[inline]
fn default() -> Self {
Self {
inner: Default::default(),
}
}
}
impl<T> From<T> for Isotope<T>
where
T: Nuclear,
T::Nucleus: Radium<Item = T> + From<T>,
{
#[inline]
fn from(val: T) -> Self {
Self {
inner: From::from(val),
}
}
}
#[repr(transparent)]
#[doc = include_str!("../doc/radon.md")]
pub struct Radon<T>
where
T: Nuclear,
Cell<T>: Radium<Item = T>,
{
pub(crate) inner: Cell<T>,
}
impl<T> Debug for Radon<T>
where
T: Nuclear + Debug,
Cell<T>: Radium<Item = T> + Debug,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
Debug::fmt(&self.inner, fmt)
}
}
impl<T> Default for Radon<T>
where
T: Nuclear + Default,
Cell<T>: Radium<Item = T> + Default,
{
#[inline]
fn default() -> Self {
Self {
inner: Default::default(),
}
}
}
impl<T> From<T> for Radon<T>
where
T: Nuclear,
Cell<T>: Radium<Item = T> + From<T>,
{
#[inline]
fn from(val: T) -> Self {
Self {
inner: From::from(val),
}
}
}
macro_rules! alias {
($($width:literal => { $(
$(@<$t:ident>)? $base:ty => $radium:ident $(=> $atom:ident)?
);+ $(;)? })+) => { $( $(
alias!(atom $width $(@<$t>)? $base => $radium $(=> $atom)?);
alias!(cell $width $(@<$t>)? $base => $radium $(=> $atom)?);
)+ )+ };
(atom $width:literal $(@<$t:ident>)? $base:ty => $radium:ident) => {};
(atom $width:literal $(@<$t:ident>)? $base:ty => $radium:ident => $atom:ident) => {
#[doc = concat!("Best-effort atomicity for `", stringify!($base), "`.")]
#[cfg(target_has_atomic = $width)]
pub type $radium$(<$t>)? = core::sync::atomic::$atom$(<$t>)?;
#[cfg(target_has_atomic = $width)]
impl$(<$t>)? Atomic for $base {
type Atom = core::sync::atomic::$atom$(<$t>)?;
}
};
(cell $width:literal $(@<$t:ident>)? $base:ty => $radium:ident => $atom:ident) => {
#[doc = concat!("Best-effort atomicity for `", stringify!($base), "`.")]
#[cfg(not(target_has_atomic = $width))]
pub type $radium$(<$t>)? = Cell<$base>;
impl$(<$t>)? Nuclear for $base {
type Nucleus = $radium$(<$t>)?;
}
};
(cell $width:literal $(@<$t:ident>)? $base:ty => $radium:ident) => {
#[doc = concat!("Best-effort atomicity for `", stringify!($base), "`.")]
pub type $radium$(<$t>)? = Cell<$base>;
impl$(<$t>)? Nuclear for $base {
type Nucleus = $radium$(<$t>)?;
}
};
}
alias! {
"8" => {
bool => RadiumBool => AtomicBool;
i8 => RadiumI8 => AtomicI8;
u8 => RadiumU8 => AtomicU8;
}
"16" => {
i16 => RadiumI16 => AtomicI16;
u16 => RadiumU16 => AtomicU16;
}
"32" => {
i32 => RadiumI32 => AtomicI32;
u32 => RadiumU32 => AtomicU32;
}
"64" => {
i64 => RadiumI64 => AtomicI64;
u64 => RadiumU64 => AtomicU64;
}
"128" => {
i128 => RadiumI128; u128 => RadiumU128; }
"ptr" => {
isize => RadiumIsize => AtomicIsize;
usize => RadiumUsize => AtomicUsize;
@<T> *mut T => RadiumPtr => AtomicPtr;
}
}
#[cfg(test)]
mod tests {
use static_assertions::*;
use super::*;
#[test]
fn atom_impls() {
#[cfg(target_has_atomic = "8")]
{
assert_impl_all!(Atom<bool>: Debug, Default, From<bool>, Send, Sync);
assert_impl_all!(Atom<i8>: Debug, Default, From<i8>, Send, Sync);
assert_impl_all!(Atom<u8>: Debug, Default, From<u8>, Send, Sync);
}
#[cfg(target_has_atomic = "16")]
{
assert_impl_all!(Atom<i16>: Debug, Default, From<i16>, Send, Sync);
assert_impl_all!(Atom<u16>: Debug, Default, From<u16>, Send, Sync);
}
#[cfg(target_has_atomic = "32")]
{
assert_impl_all!(Atom<i32>: Debug, Default, From<i32>, Send, Sync);
assert_impl_all!(Atom<u32>: Debug, Default, From<u32>, Send, Sync);
}
#[cfg(target_has_atomic = "64")]
{
assert_impl_all!(Atom<i64>: Debug, Default, From<i64>, Send, Sync);
assert_impl_all!(Atom<u64>: Debug, Default, From<u64>, Send, Sync);
}
#[cfg(target_has_atomic = "ptr")]
{
assert_impl_all!(Atom<isize>: Debug, Default, From<isize>, Send, Sync);
assert_impl_all!(Atom<usize>: Debug, Default, From<usize>, Send, Sync);
assert_impl_all!(Atom<*mut ()>: Debug, From<*mut ()>, Send, Sync);
}
}
#[test]
fn isotope_impls() {
assert_impl_all!(Isotope<bool>: Debug, Default, From<bool>);
assert_impl_all!(Isotope<i8>: Debug, Default, From<i8>);
assert_impl_all!(Isotope<u8>: Debug, Default, From<u8>);
assert_impl_all!(Isotope<i16>: Debug, Default, From<i16>);
assert_impl_all!(Isotope<u16>: Debug, Default, From<u16>);
assert_impl_all!(Isotope<i32>: Debug, Default, From<i32>);
assert_impl_all!(Isotope<u32>: Debug, Default, From<u32>);
assert_impl_all!(Isotope<i64>: Debug, Default, From<i64>);
assert_impl_all!(Isotope<u64>: Debug, Default, From<u64>);
assert_impl_all!(Isotope<i128>: Debug, Default, From<i128>);
assert_impl_all!(Isotope<u128>: Debug, Default, From<u128>);
assert_impl_all!(Isotope<isize>: Debug, Default, From<isize>);
assert_impl_all!(Isotope<usize>: Debug, Default, From<usize>);
assert_impl_all!(Isotope<*mut ()>: Debug, From<*mut ()>);
}
#[test]
fn radon_impls() {
assert_impl_all!(Radon<bool>: Debug, Default, From<bool>);
assert_impl_all!(Radon<i8>: Debug, Default, From<i8>);
assert_impl_all!(Radon<u8>: Debug, Default, From<u8>);
assert_impl_all!(Radon<i16>: Debug, Default, From<i16>);
assert_impl_all!(Radon<u16>: Debug, Default, From<u16>);
assert_impl_all!(Radon<i32>: Debug, Default, From<i32>);
assert_impl_all!(Radon<u32>: Debug, Default, From<u32>);
assert_impl_all!(Radon<i64>: Debug, Default, From<i64>);
assert_impl_all!(Radon<u64>: Debug, Default, From<u64>);
assert_impl_all!(Radon<i128>: Debug, Default, From<i128>);
assert_impl_all!(Radon<u128>: Debug, Default, From<u128>);
assert_impl_all!(Radon<isize>: Debug, Default, From<isize>);
assert_impl_all!(Radon<usize>: Debug, Default, From<usize>);
assert_impl_all!(Radon<*mut ()>: Debug, From<*mut ()>);
assert_not_impl_any!(Radon<bool>: Sync);
assert_not_impl_any!(Radon<i8>: Sync);
assert_not_impl_any!(Radon<u8>: Sync);
assert_not_impl_any!(Radon<i16>: Sync);
assert_not_impl_any!(Radon<u16>: Sync);
assert_not_impl_any!(Radon<i32>: Sync);
assert_not_impl_any!(Radon<u32>: Sync);
assert_not_impl_any!(Radon<i64>: Sync);
assert_not_impl_any!(Radon<u64>: Sync);
assert_not_impl_any!(Radon<i128>: Sync);
assert_not_impl_any!(Radon<u128>: Sync);
assert_not_impl_any!(Radon<isize>: Sync);
assert_not_impl_any!(Radon<usize>: Sync);
assert_not_impl_any!(Radon<*mut ()>: Sync);
}
#[test]
fn isotope_atomic() {
cfg_if::cfg_if! {
if #[cfg(target_has_atomic = "8")] {
assert_impl_all!(Isotope<bool>: Sync);
assert_impl_all!(Isotope<i8>: Sync);
assert_impl_all!(Isotope<u8>: Sync);
}
else {
assert_not_impl_any!(Isotope<bool>: Sync);
assert_not_impl_any!(Isotope<i8>: Sync);
assert_not_impl_any!(Isotope<u8>: Sync);
}
}
cfg_if::cfg_if! {
if #[cfg(target_has_atomic = "16")] {
assert_impl_all!(Isotope<i16>: Sync);
assert_impl_all!(Isotope<u16>: Sync);
}
else {
assert_not_impl_any!(Isotope<i16>: Sync);
assert_not_impl_any!(Isotope<u16>: Sync);
}
}
cfg_if::cfg_if! {
if #[cfg(target_has_atomic = "32")] {
assert_impl_all!(Isotope<i32>: Sync);
assert_impl_all!(Isotope<u32>: Sync);
}
else {
assert_not_impl_any!(Isotope<i32>: Sync);
assert_not_impl_any!(Isotope<u32>: Sync);
}
}
cfg_if::cfg_if! {
if #[cfg(target_has_atomic = "64")] {
assert_impl_all!(Isotope<i64>: Sync);
assert_impl_all!(Isotope<u64>: Sync);
}
else {
assert_not_impl_any!(Isotope<i64>: Sync);
assert_not_impl_any!(Isotope<u64>: Sync);
}
}
cfg_if::cfg_if! {
if #[cfg(target_has_atomic = "ptr")] {
assert_impl_all!(Isotope<isize>: Sync);
assert_impl_all!(Isotope<usize>: Sync);
assert_impl_all!(Isotope<*mut ()>: Sync);
}
else {
assert_not_impl_any!(Isotope<isize>: Sync);
assert_not_impl_any!(Isotope<usize>: Sync);
assert_not_impl_any!(Isotope<*mut ()>: Sync);
}
}
assert_not_impl_any!(Isotope<i128>: Sync);
assert_not_impl_any!(Isotope<u128>: Sync);
}
}