use std::{fmt::Debug, sync::atomic::Ordering};
crate::cfg_loom! {
use std::cell::Cell;
}
atomic_int!(AtomicU8(u8));
atomic_int!(AtomicU16(u16));
atomic_int!(AtomicU32(u32));
atomic_int!(AtomicU64(u64));
atomic_int!(AtomicUsize(usize));
atomic_int!(AtomicI8(i8));
atomic_int!(AtomicI16(i16));
atomic_int!(AtomicI32(i32));
atomic_int!(AtomicI64(i64));
atomic_int!(AtomicIsize(isize));
pub struct AtomicBool {
v: Cell<bool>,
}
impl From<bool> for AtomicBool {
fn from(val: bool) -> Self {
Self::new(val)
}
}
impl Default for AtomicBool {
fn default() -> Self {
Self::new(false)
}
}
impl Debug for AtomicBool {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.v.get(), f)
}
}
impl AtomicBool {
#[cfg(not(loom))]
pub const fn new(val: bool) -> Self {
Self { v: Cell::new(val) }
}
#[cfg(loom)]
pub fn new(val: bool) -> Self {
Self { v: Cell::new(val) }
}
#[cfg(not(loom))]
pub fn get_mut(&mut self) -> &mut bool {
self.v.get_mut()
}
pub fn load(&self, _: Ordering) -> bool {
self.v.get()
}
pub fn store(&self, val: bool, _: Ordering) {
self.v.set(val)
}
pub fn swap(&self, val: bool, _: Ordering) -> bool {
self.v.replace(val)
}
pub fn compare_exchange(
&self,
current: bool,
new: bool,
_: Ordering,
_: Ordering,
) -> Result<bool, bool> {
let old = self.v.get();
if old == current {
self.v.set(new);
Ok(old)
} else {
Err(old)
}
}
pub fn compare_exchange_weak(
&self,
current: bool,
new: bool,
success: Ordering,
failure: Ordering,
) -> Result<bool, bool> {
self.compare_exchange(current, new, success, failure)
}
pub fn fetch_update<F>(&self, _: Ordering, _: Ordering, mut f: F) -> Result<bool, bool>
where
F: FnMut(bool) -> Option<bool>,
{
let curr = self.v.get();
if let Some(new) = f(curr) {
self.v.set(new);
Ok(curr)
} else {
Err(curr)
}
}
pub fn fetch_and(&self, val: bool, _: Ordering) -> bool {
let old = self.v.get();
self.v.set(old & val);
old
}
pub fn fetch_nand(&self, val: bool, _: Ordering) -> bool {
let old = self.v.get();
self.v.set(!(old & val));
old
}
pub fn fetch_not(&self, _: Ordering) -> bool {
let old = self.v.get();
self.v.set(!old);
old
}
pub fn fetch_or(&self, val: bool, _: Ordering) -> bool {
let old = self.v.get();
self.v.set(old | val);
old
}
pub fn fetch_xor(&self, val: bool, _: Ordering) -> bool {
let old = self.v.get();
self.v.set(old ^ val);
old
}
}
macro_rules! atomic_int {
($t:ident($i:ty)) => {
#[doc = concat!("A singlethreaded [`", stringify!($t), "`] based on [`Cell`](std::cell::Cell)\n\n")]
#[doc = concat!("\n\n[`", stringify!($t), "`]: std::sync::atomic::", stringify!($t))]
#[repr(transparent)]
pub struct $t {
v: Cell<$i>,
}
impl From<$i> for $t {
fn from(val: $i) -> Self {
Self::new(val)
}
}
impl Default for $t {
fn default() -> Self {
Self::new(0)
}
}
impl Debug for $t {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.v.get(), f)
}
}
impl $t {
#[cfg(not(loom))]
#[doc = concat!("Creates a new [`", stringify!($t), "`]")]
pub const fn new(val: $i) -> Self {
Self { v: Cell::new(val) }
}
#[cfg(loom)]
#[doc = concat!("Creates a new [`", stringify!($t), "`]")]
pub fn new(val: $i) -> Self {
Self { v: Cell::new(val) }
}
#[cfg(not(loom))]
pub fn get_mut(&mut self) -> &mut $i {
self.v.get_mut()
}
pub fn load(&self, _: Ordering) -> $i {
self.v.get()
}
pub fn store(&self, val: $i, _: Ordering) {
self.v.set(val)
}
pub fn swap(&self, val: $i, _: Ordering) -> $i {
self.v.replace(val)
}
pub fn compare_exchange(
&self,
current: $i,
new: $i,
_: Ordering,
_: Ordering,
) -> Result<$i, $i> {
let old = self.v.get();
if old == current {
self.v.set(new);
Ok(old)
} else {
Err(old)
}
}
pub fn compare_exchange_weak(
&self,
current: $i,
new: $i,
success: Ordering,
failure: Ordering,
) -> Result<$i, $i> {
self.compare_exchange(current, new, success, failure)
}
pub fn fetch_update<F>(&self, _: Ordering, _: Ordering, mut f: F) -> Result<$i, $i>
where
F: FnMut($i) -> Option<$i>,
{
let curr = self.v.get();
if let Some(new) = f(curr) {
self.v.set(new);
Ok(curr)
} else {
Err(curr)
}
}
pub fn fetch_add(&self, val: $i, _: Ordering) -> $i {
self.v.replace(self.v.get() + val)
}
pub fn fetch_sub(&self, val: $i, _: Ordering) -> $i {
self.v.replace(self.v.get() - val)
}
pub fn fetch_and(&self, val: $i, _: Ordering) -> $i {
self.v.replace(self.v.get() & val)
}
pub fn fetch_nand(&self, val: $i, _: Ordering) -> $i {
self.v.replace(!(self.v.get() & val))
}
pub fn fetch_or(&self, val: $i, _: Ordering) -> $i {
self.v.replace(self.v.get() | val)
}
pub fn fetch_xor(&self, val: $i, _: Ordering) -> $i {
self.v.replace(self.v.get() ^ val)
}
pub fn fetch_max(&self, val: $i, _: Ordering) -> $i {
self.v.replace(self.v.get().max(val))
}
pub fn fetch_min(&self, val: $i, _: Ordering) -> $i {
self.v.replace(self.v.get().min(val))
}
}
};
}
use atomic_int;