use std::sync::atomic::{
AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicPtr, AtomicU8,
AtomicU16, AtomicU32, AtomicU64, AtomicUsize, Ordering,
};
pub trait AtomicPrimitive: Sync + Send + Sized {
type InnerPrimitive: Default;
fn new(value: Self::InnerPrimitive) -> Self;
fn load(&self) -> Self::InnerPrimitive;
fn store(&self, value: Self::InnerPrimitive);
fn new_default() -> Self {
Self::new(Default::default())
}
}
macro_rules! impl_atomic_primitive {
($atomic:ty, $inner:ty) => {
impl AtomicPrimitive for $atomic {
type InnerPrimitive = $inner;
fn new(value: $inner) -> Self {
<$atomic>::new(value)
}
fn load(&self) -> $inner {
self.load(Ordering::Relaxed)
}
fn store(&self, value: $inner) {
self.store(value, Ordering::Relaxed)
}
}
};
}
impl_atomic_primitive!(AtomicBool, bool);
impl_atomic_primitive!(AtomicU8, u8);
impl_atomic_primitive!(AtomicI8, i8);
impl_atomic_primitive!(AtomicU16, u16);
impl_atomic_primitive!(AtomicI16, i16);
impl_atomic_primitive!(AtomicU32, u32);
impl_atomic_primitive!(AtomicI32, i32);
impl_atomic_primitive!(AtomicU64, u64);
impl_atomic_primitive!(AtomicI64, i64);
impl_atomic_primitive!(AtomicUsize, usize);
impl_atomic_primitive!(AtomicIsize, isize);
impl<T> AtomicPrimitive for AtomicPtr<T> {
type InnerPrimitive = *mut T;
fn new(value: *mut T) -> Self {
AtomicPtr::new(value)
}
fn load(&self) -> *mut T {
self.load(Ordering::Relaxed)
}
fn store(&self, value: *mut T) {
self.store(value, Ordering::Relaxed)
}
}
#[derive(Debug, Default)]
pub struct AtomicConstPtr<T> {
p: AtomicPtr<T>,
}
impl<T> AtomicPrimitive for AtomicConstPtr<T> {
type InnerPrimitive = *const T;
fn new(value: *const T) -> Self {
Self {
p: AtomicPtr::new(value as *mut T),
}
}
fn load(&self) -> *const T {
self.p.load(Ordering::Relaxed) as *const T
}
fn store(&self, value: *const T) {
self.p.store(value as *mut T, Ordering::Relaxed)
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AtomicUnit;
impl AtomicPrimitive for AtomicUnit {
type InnerPrimitive = ();
fn new(_: ()) -> Self {
Self
}
fn load(&self) -> Self::InnerPrimitive {}
fn store(&self, _: Self::InnerPrimitive) {}
}
pub trait Payload:
From<<Self::UnderlyingAtomic as AtomicPrimitive>::InnerPrimitive>
+ Into<<Self::UnderlyingAtomic as AtomicPrimitive>::InnerPrimitive>
+ Copy
{
type UnderlyingAtomic: AtomicPrimitive;
}
macro_rules! impl_payload {
($inner:ty, $atomic:ty) => {
impl Payload for $inner {
type UnderlyingAtomic = $atomic;
}
};
}
impl_payload!((), AtomicUnit);
impl_payload!(bool, AtomicBool);
impl_payload!(u8, AtomicU8);
impl_payload!(i8, AtomicI8);
impl_payload!(u16, AtomicU16);
impl_payload!(i16, AtomicI16);
impl_payload!(u32, AtomicU32);
impl_payload!(i32, AtomicI32);
impl_payload!(u64, AtomicU64);
impl_payload!(i64, AtomicI64);
impl_payload!(usize, AtomicUsize);
impl_payload!(isize, AtomicIsize);
impl<T> Payload for *mut T {
type UnderlyingAtomic = AtomicPtr<T>;
}
impl<T> Payload for *const T {
type UnderlyingAtomic = AtomicConstPtr<T>;
}