use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Debug, Default)]
pub struct Counter(AtomicU64);
impl Counter {
pub const fn new() -> Self {
Self(AtomicU64::new(0))
}
pub fn get(&self) -> u64 {
self.0.load(Ordering::Relaxed)
}
pub fn inc(&self) {
self.0.fetch_add(1, Ordering::Relaxed);
}
pub fn add(&self, n: u64) {
self.0.fetch_add(n, Ordering::Relaxed);
}
}
impl Clone for Counter {
fn clone(&self) -> Self {
Self(AtomicU64::new(self.get()))
}
}
impl PartialEq for Counter {
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
}
impl Eq for Counter {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_is_zero() {
assert_eq!(Counter::default().get(), 0);
}
#[test]
fn inc_bumps_by_one() {
let c = Counter::new();
c.inc();
c.inc();
c.inc();
assert_eq!(c.get(), 3);
}
#[test]
fn add_bumps_by_n() {
let c = Counter::new();
c.add(10);
c.add(7);
assert_eq!(c.get(), 17);
}
#[test]
fn clone_is_independent_snapshot() {
let a = Counter::new();
a.inc();
let b = a.clone();
assert_eq!(a.get(), 1);
assert_eq!(b.get(), 1);
a.inc();
b.inc();
b.inc();
assert_eq!(a.get(), 2);
assert_eq!(b.get(), 3);
}
#[test]
fn partial_eq_uses_current_values() {
let a = Counter::new();
let b = Counter::new();
assert_eq!(a, b);
a.inc();
assert_ne!(a, b);
b.inc();
assert_eq!(a, b);
}
}