use core::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
AtomicU64, AtomicU8, AtomicUsize, Ordering,
};
pub(crate) mod sealed {
pub trait Sealed {}
}
pub trait Atomic: sealed::Sealed {
type Value: Copy;
#[doc(hidden)]
fn new_atomic(value: Self::Value) -> Self;
#[doc(hidden)]
fn atomic_load(&self, order: Ordering) -> Self::Value;
#[doc(hidden)]
fn atomic_store(&self, value: Self::Value, order: Ordering);
#[doc(hidden)]
fn atomic_swap(&self, value: Self::Value, order: Ordering) -> Self::Value;
#[doc(hidden)]
fn atomic_compare_exchange(
&self,
current: Self::Value,
new: Self::Value,
success: Ordering,
failure: Ordering,
) -> Result<Self::Value, Self::Value>;
#[doc(hidden)]
fn atomic_get_mut(&mut self) -> &mut Self::Value;
#[doc(hidden)]
fn atomic_into_inner(self) -> Self::Value;
#[doc(hidden)]
fn value_ptr(&self) -> *mut Self::Value;
#[doc(hidden)]
fn atomic_fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> Result<Self::Value, Self::Value>
where
F: FnMut(Self::Value) -> Option<Self::Value>;
}
pub trait AtomicInt: Atomic {
#[doc(hidden)]
fn atomic_fetch_add(&self, value: Self::Value, order: Ordering) -> Self::Value;
#[doc(hidden)]
fn atomic_fetch_sub(&self, value: Self::Value, order: Ordering) -> Self::Value;
#[doc(hidden)]
fn atomic_fetch_and(&self, value: Self::Value, order: Ordering) -> Self::Value;
#[doc(hidden)]
fn atomic_fetch_or(&self, value: Self::Value, order: Ordering) -> Self::Value;
#[doc(hidden)]
fn atomic_fetch_xor(&self, value: Self::Value, order: Ordering) -> Self::Value;
#[doc(hidden)]
fn atomic_fetch_nand(&self, value: Self::Value, order: Ordering) -> Self::Value;
#[doc(hidden)]
fn atomic_fetch_max(&self, value: Self::Value, order: Ordering) -> Self::Value;
#[doc(hidden)]
fn atomic_fetch_min(&self, value: Self::Value, order: Ordering) -> Self::Value;
}
macro_rules! impl_atomic_base {
($atomic:ty, $value:ty) => {
impl sealed::Sealed for $atomic {}
impl Atomic for $atomic {
type Value = $value;
#[inline]
fn new_atomic(value: $value) -> Self {
<$atomic>::new(value)
}
#[inline]
fn atomic_load(&self, order: Ordering) -> $value {
self.load(order)
}
#[inline]
fn atomic_store(&self, value: $value, order: Ordering) {
self.store(value, order);
}
#[inline]
fn atomic_swap(&self, value: $value, order: Ordering) -> $value {
self.swap(value, order)
}
#[inline]
fn atomic_compare_exchange(
&self,
current: $value,
new: $value,
success: Ordering,
failure: Ordering,
) -> Result<$value, $value> {
self.compare_exchange(current, new, success, failure)
}
#[inline]
fn atomic_get_mut(&mut self) -> &mut $value {
self.get_mut()
}
#[inline]
fn atomic_into_inner(self) -> $value {
self.into_inner()
}
#[inline]
fn value_ptr(&self) -> *mut $value {
core::ptr::from_ref(self).cast::<$value>().cast_mut()
}
#[inline]
fn atomic_fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> Result<$value, $value>
where
F: FnMut($value) -> Option<$value>,
{
self.fetch_update(set_order, fetch_order, f)
}
}
};
}
macro_rules! impl_atomic_int {
($atomic:ty, $value:ty) => {
impl_atomic_base!($atomic, $value);
impl AtomicInt for $atomic {
#[inline]
fn atomic_fetch_add(&self, value: $value, order: Ordering) -> $value {
self.fetch_add(value, order)
}
#[inline]
fn atomic_fetch_sub(&self, value: $value, order: Ordering) -> $value {
self.fetch_sub(value, order)
}
#[inline]
fn atomic_fetch_and(&self, value: $value, order: Ordering) -> $value {
self.fetch_and(value, order)
}
#[inline]
fn atomic_fetch_or(&self, value: $value, order: Ordering) -> $value {
self.fetch_or(value, order)
}
#[inline]
fn atomic_fetch_xor(&self, value: $value, order: Ordering) -> $value {
self.fetch_xor(value, order)
}
#[inline]
fn atomic_fetch_nand(&self, value: $value, order: Ordering) -> $value {
self.fetch_nand(value, order)
}
#[inline]
fn atomic_fetch_max(&self, value: $value, order: Ordering) -> $value {
self.fetch_max(value, order)
}
#[inline]
fn atomic_fetch_min(&self, value: $value, order: Ordering) -> $value {
self.fetch_min(value, order)
}
}
};
}
impl_atomic_int!(AtomicUsize, usize);
impl_atomic_int!(AtomicIsize, isize);
impl_atomic_int!(AtomicU32, u32);
impl_atomic_int!(AtomicI32, i32);
#[cfg(target_has_atomic = "64")]
impl_atomic_int!(AtomicU64, u64);
#[cfg(target_has_atomic = "64")]
impl_atomic_int!(AtomicI64, i64);
impl_atomic_int!(AtomicU8, u8);
impl_atomic_int!(AtomicI8, i8);
impl_atomic_int!(AtomicU16, u16);
impl_atomic_int!(AtomicI16, i16);
impl_atomic_base!(AtomicBool, bool);