mod internal;
pub mod ordering;
mod predefine;
pub use internal::AtomicImpl;
pub use ordering::{Acquire, Full, Relaxed, Release};
pub(crate) use internal::{AtomicArithmeticOps, AtomicBasicOps, AtomicExchangeOps};
use crate::build_error;
use internal::AtomicRepr;
use ordering::OrderingType;
#[repr(transparent)]
pub struct Atomic<T: AtomicType>(AtomicRepr<T::Repr>);
unsafe impl<T: AtomicType> Sync for Atomic<T> {}
pub unsafe trait AtomicType: Sized + Send + Copy {
type Repr: AtomicImpl;
}
pub unsafe trait AtomicAdd<Rhs = Self>: AtomicType {
fn rhs_into_delta(rhs: Rhs) -> <Self::Repr as AtomicImpl>::Delta;
}
#[inline(always)]
const fn into_repr<T: AtomicType>(v: T) -> T::Repr {
unsafe { core::mem::transmute_copy(&v) }
}
#[inline(always)]
const unsafe fn from_repr<T: AtomicType>(r: T::Repr) -> T {
unsafe { core::mem::transmute_copy(&r) }
}
impl<T: AtomicType> Atomic<T> {
pub const fn new(v: T) -> Self {
Self(AtomicRepr::new(into_repr(v)))
}
pub unsafe fn from_ptr<'a>(ptr: *mut T) -> &'a Self
where
T: Sync,
{
unsafe { &*ptr.cast::<Self>() }
}
pub const fn as_ptr(&self) -> *mut T {
self.0.as_ptr().cast()
}
pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.0.as_ptr().cast() }
}
}
impl<T: AtomicType> Atomic<T>
where
T::Repr: AtomicBasicOps,
{
#[doc(alias("atomic_read", "atomic64_read"))]
#[inline(always)]
pub fn load<Ordering: ordering::AcquireOrRelaxed>(&self, _: Ordering) -> T {
let v = {
match Ordering::TYPE {
OrderingType::Relaxed => T::Repr::atomic_read(&self.0),
OrderingType::Acquire => T::Repr::atomic_read_acquire(&self.0),
_ => build_error!("Wrong ordering"),
}
};
unsafe { from_repr(v) }
}
#[doc(alias("atomic_set", "atomic64_set"))]
#[inline(always)]
pub fn store<Ordering: ordering::ReleaseOrRelaxed>(&self, v: T, _: Ordering) {
let v = into_repr(v);
match Ordering::TYPE {
OrderingType::Relaxed => T::Repr::atomic_set(&self.0, v),
OrderingType::Release => T::Repr::atomic_set_release(&self.0, v),
_ => build_error!("Wrong ordering"),
}
}
}
impl<T: AtomicType + core::fmt::Debug> core::fmt::Debug for Atomic<T>
where
T::Repr: AtomicBasicOps,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.load(Relaxed), f)
}
}
impl<T: AtomicType> Atomic<T>
where
T::Repr: AtomicExchangeOps,
{
#[doc(alias("atomic_xchg", "atomic64_xchg", "swap"))]
#[inline(always)]
pub fn xchg<Ordering: ordering::Ordering>(&self, v: T, _: Ordering) -> T {
let v = into_repr(v);
let ret = {
match Ordering::TYPE {
OrderingType::Full => T::Repr::atomic_xchg(&self.0, v),
OrderingType::Acquire => T::Repr::atomic_xchg_acquire(&self.0, v),
OrderingType::Release => T::Repr::atomic_xchg_release(&self.0, v),
OrderingType::Relaxed => T::Repr::atomic_xchg_relaxed(&self.0, v),
}
};
unsafe { from_repr(ret) }
}
#[doc(alias(
"atomic_cmpxchg",
"atomic64_cmpxchg",
"atomic_try_cmpxchg",
"atomic64_try_cmpxchg",
"compare_exchange"
))]
#[inline(always)]
pub fn cmpxchg<Ordering: ordering::Ordering>(
&self,
mut old: T,
new: T,
o: Ordering,
) -> Result<T, T> {
if self.try_cmpxchg(&mut old, new, o) {
Ok(old)
} else {
Err(old)
}
}
#[inline(always)]
fn try_cmpxchg<Ordering: ordering::Ordering>(&self, old: &mut T, new: T, _: Ordering) -> bool {
let mut tmp = into_repr(*old);
let new = into_repr(new);
let ret = {
match Ordering::TYPE {
OrderingType::Full => T::Repr::atomic_try_cmpxchg(&self.0, &mut tmp, new),
OrderingType::Acquire => {
T::Repr::atomic_try_cmpxchg_acquire(&self.0, &mut tmp, new)
}
OrderingType::Release => {
T::Repr::atomic_try_cmpxchg_release(&self.0, &mut tmp, new)
}
OrderingType::Relaxed => {
T::Repr::atomic_try_cmpxchg_relaxed(&self.0, &mut tmp, new)
}
}
};
*old = unsafe { from_repr(tmp) };
ret
}
}
impl<T: AtomicType> Atomic<T>
where
T::Repr: AtomicArithmeticOps,
{
#[inline(always)]
pub fn add<Rhs>(&self, v: Rhs, _: ordering::Relaxed)
where
T: AtomicAdd<Rhs>,
{
let v = T::rhs_into_delta(v);
T::Repr::atomic_add(&self.0, v);
}
#[inline(always)]
pub fn fetch_add<Rhs, Ordering: ordering::Ordering>(&self, v: Rhs, _: Ordering) -> T
where
T: AtomicAdd<Rhs>,
{
let v = T::rhs_into_delta(v);
let ret = {
match Ordering::TYPE {
OrderingType::Full => T::Repr::atomic_fetch_add(&self.0, v),
OrderingType::Acquire => T::Repr::atomic_fetch_add_acquire(&self.0, v),
OrderingType::Release => T::Repr::atomic_fetch_add_release(&self.0, v),
OrderingType::Relaxed => T::Repr::atomic_fetch_add_relaxed(&self.0, v),
}
};
unsafe { from_repr(ret) }
}
}