use std::fmt;
use std::sync::atomic::{
AtomicIsize as StdAtomicIsize,
Ordering,
};
#[repr(transparent)]
pub struct AtomicSignedCount {
inner: StdAtomicIsize,
}
impl AtomicSignedCount {
#[inline]
pub const fn new(value: isize) -> Self {
Self {
inner: StdAtomicIsize::new(value),
}
}
#[inline]
pub const fn zero() -> Self {
Self::new(0)
}
#[inline]
pub fn get(&self) -> isize {
self.inner.load(Ordering::Acquire)
}
#[inline]
pub fn is_zero(&self) -> bool {
self.get() == 0
}
#[inline]
pub fn is_positive(&self) -> bool {
self.get() > 0
}
#[inline]
pub fn is_negative(&self) -> bool {
self.get() < 0
}
#[inline]
pub fn inc(&self) -> isize {
self.add(1)
}
#[inline]
pub fn dec(&self) -> isize {
self.sub(1)
}
#[inline]
pub fn add(&self, delta: isize) -> isize {
self.try_add(delta).expect("atomic signed counter overflow")
}
#[inline]
pub fn try_add(&self, delta: isize) -> Option<isize> {
self.try_update(|current| current.checked_add(delta))
}
#[inline]
pub fn sub(&self, delta: isize) -> isize {
self.try_sub(delta).expect("atomic signed counter overflow")
}
#[inline]
pub fn try_sub(&self, delta: isize) -> Option<isize> {
self.try_update(|current| current.checked_sub(delta))
}
#[inline]
fn try_update<F>(&self, update: F) -> Option<isize>
where
F: Fn(isize) -> Option<isize>,
{
let mut current = self.get();
loop {
let next = update(current)?;
match self.inner.compare_exchange_weak(
current,
next,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return Some(next),
Err(actual) => current = actual,
}
}
}
}
impl Default for AtomicSignedCount {
#[inline]
fn default() -> Self {
Self::zero()
}
}
impl From<isize> for AtomicSignedCount {
#[inline]
fn from(value: isize) -> Self {
Self::new(value)
}
}
impl fmt::Debug for AtomicSignedCount {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AtomicSignedCount")
.field("value", &self.get())
.finish()
}
}
impl fmt::Display for AtomicSignedCount {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.get())
}
}