#[macro_export]
macro_rules! test_atomic_integer {
($atomic_type:ident, $value_type:ty, $test_mod:ident) => {
mod $test_mod {
use qubit_atomic::atomic::{
$atomic_type,
Atomic,
AtomicNumber,
};
use std::sync::Arc;
use std::thread;
#[test]
fn test_new() {
let atomic = <$atomic_type>::new(42);
assert_eq!(atomic.load(), 42);
}
#[test]
fn test_default() {
let atomic = <$atomic_type>::default();
assert_eq!(atomic.load(), 0);
}
#[test]
fn test_from() {
let atomic = <$atomic_type>::from(100);
assert_eq!(atomic.load(), 100);
}
#[test]
fn test_get_set() {
let atomic = <$atomic_type>::new(0);
atomic.store(42);
assert_eq!(atomic.load(), 42);
atomic.store(10);
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_swap() {
let atomic = <$atomic_type>::new(10);
let old = atomic.swap(20);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 20);
}
#[test]
fn test_compare_and_set_success() {
let atomic = <$atomic_type>::new(10);
assert!(atomic.compare_set(10, 20).is_ok());
assert_eq!(atomic.load(), 20);
}
#[test]
fn test_compare_and_set_failure() {
let atomic = <$atomic_type>::new(10);
match atomic.compare_set(15, 20) {
Ok(_) => panic!("Should fail"),
Err(actual) => assert_eq!(actual, 10),
}
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_compare_and_exchange() {
let atomic = <$atomic_type>::new(10);
let prev = atomic.compare_exchange(10, 20);
assert_eq!(prev, 10);
assert_eq!(atomic.load(), 20);
let prev = atomic.compare_exchange(10, 30);
assert_eq!(prev, 20);
assert_eq!(atomic.load(), 20);
}
#[test]
fn test_get_and_increment() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_inc();
assert_eq!(old, 10);
assert_eq!(atomic.load(), 11);
}
#[test]
fn test_get_and_decrement() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_dec();
assert_eq!(old, 10);
assert_eq!(atomic.load(), 9);
}
#[test]
fn test_get_and_add() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_add(5);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 15);
}
#[test]
fn test_get_and_sub() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_sub(3);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 7);
}
#[test]
fn test_fetch_mul() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_mul(3);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 30);
}
#[test]
fn test_fetch_mul_zero() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_mul(0);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 0);
}
#[test]
fn test_fetch_mul_one() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_mul(1);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_fetch_div() {
let atomic = <$atomic_type>::new(30);
let old = atomic.fetch_div(3);
assert_eq!(old, 30);
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_fetch_div_one() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_div(1);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 10);
}
#[test]
#[should_panic(expected = "division by zero")]
fn test_fetch_div_by_zero() {
let atomic = <$atomic_type>::new(10);
atomic.fetch_div(0);
}
#[test]
fn test_get_and_bit_and() {
let atomic = <$atomic_type>::new(0b1111);
let old = atomic.fetch_and(0b1100);
assert_eq!(old, 0b1111);
assert_eq!(atomic.load(), 0b1100);
}
#[test]
fn test_get_and_bit_or() {
let atomic = <$atomic_type>::new(0b1100);
let old = atomic.fetch_or(0b0011);
assert_eq!(old, 0b1100);
assert_eq!(atomic.load(), 0b1111);
}
#[test]
fn test_get_and_bit_xor() {
let atomic = <$atomic_type>::new(0b1100);
let old = atomic.fetch_xor(0b0110);
assert_eq!(old, 0b1100);
assert_eq!(atomic.load(), 0b1010);
}
#[test]
fn test_get_and_bit_not() {
let value: $value_type = 42;
let atomic = <$atomic_type>::new(value);
let old = atomic.fetch_not();
assert_eq!(old, value);
assert_eq!(atomic.load(), !value);
}
#[test]
fn test_bit_not_twice() {
let value: $value_type = 42;
let atomic = <$atomic_type>::new(value);
atomic.fetch_not();
atomic.fetch_not();
assert_eq!(atomic.load(), value);
}
#[test]
fn test_get_and_update() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_update(|x| x * 2);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 20);
}
#[test]
fn test_get_and_accumulate() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_accumulate(5, |a, b| a + b);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 15);
}
#[test]
fn test_get_and_max() {
let atomic = <$atomic_type>::new(10);
atomic.fetch_max(20);
assert_eq!(atomic.load(), 20);
atomic.fetch_max(15);
assert_eq!(atomic.load(), 20);
}
#[test]
fn test_get_and_min() {
let atomic = <$atomic_type>::new(10);
atomic.fetch_min(5);
assert_eq!(atomic.load(), 5);
atomic.fetch_min(8);
assert_eq!(atomic.load(), 5);
}
#[test]
fn test_concurrent_increment() {
let counter = Arc::new(<$atomic_type>::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = counter.clone();
let handle = thread::spawn(move || {
for _ in 0..10 {
counter.fetch_inc();
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(counter.load(), 100 as $value_type);
}
#[test]
fn test_concurrent_get_and_increment() {
let counter = Arc::new(<$atomic_type>::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = counter.clone();
let handle = thread::spawn(move || {
for _ in 0..10 {
counter.fetch_inc();
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(counter.load(), 100 as $value_type);
}
#[test]
fn test_concurrent_get_and_decrement() {
let counter = Arc::new(<$atomic_type>::new(100 as $value_type));
let mut handles = vec![];
for _ in 0..10 {
let counter = counter.clone();
let handle = thread::spawn(move || {
for _ in 0..10 {
counter.fetch_dec();
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(counter.load(), 0);
}
#[test]
fn test_concurrent_get_and_add() {
let counter = Arc::new(<$atomic_type>::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = counter.clone();
let handle = thread::spawn(move || {
for _ in 0..10 {
counter.fetch_add(1);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(counter.load(), 100 as $value_type);
}
#[test]
fn test_concurrent_get_and_accumulate_high_contention() {
let counter = Arc::new(<$atomic_type>::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = counter.clone();
let handle = thread::spawn(move || {
for _ in 0..10 {
counter.fetch_accumulate(1, |a, b| a.wrapping_add(b));
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(counter.load(), 100 as $value_type);
}
#[test]
fn test_concurrent_get_and_update_high_contention() {
let counter = Arc::new(<$atomic_type>::new(0));
let mut handles = vec![];
for _ in 0..20 {
let counter = counter.clone();
let handle = thread::spawn(move || {
for _ in 0..5 {
counter.fetch_update(|x| x.wrapping_add(1));
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(counter.load(), 100 as $value_type);
}
#[test]
fn test_concurrent_cas() {
let atomic = Arc::new(<$atomic_type>::new(0));
let mut handles = vec![];
for i in 0..10 {
let atomic = atomic.clone();
let handle = thread::spawn(move || {
let mut current = atomic.load();
loop {
match atomic.compare_set_weak(current, current + 1) {
Ok(_) => return i,
Err(actual) => current = actual,
}
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_concurrent_fetch_mul() {
let atomic = Arc::new(<$atomic_type>::new(1));
let mut handles = vec![];
for _ in 0..5 {
let atomic = atomic.clone();
let handle = thread::spawn(move || {
atomic.fetch_mul(2);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(atomic.load(), 32);
}
#[test]
fn test_concurrent_fetch_div() {
let atomic = Arc::new(<$atomic_type>::new(32));
let mut handles = vec![];
for _ in 0..5 {
let atomic = atomic.clone();
let handle = thread::spawn(move || {
atomic.fetch_div(2);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(atomic.load(), 1);
}
#[test]
fn test_concurrent_compare_exchange_weak() {
let atomic = Arc::new(<$atomic_type>::new(0));
let mut handles = vec![];
for _ in 0..10 {
let atomic = atomic.clone();
let handle = thread::spawn(move || {
let mut current = atomic.load();
loop {
let prev = atomic.compare_and_exchange_weak(current, current + 1);
if prev == current {
break;
}
current = prev;
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_trait_atomic() {
fn test_atomic<T: Atomic<Value = $value_type>>(atomic: &T) {
atomic.store(42);
assert_eq!(atomic.load(), 42);
let old = atomic.swap(100);
assert_eq!(old, 42);
}
let atomic = <$atomic_type>::new(0);
test_atomic(&atomic);
}
#[test]
fn test_trait_fetch_update() {
let atomic = <$atomic_type>::new(0);
let old = atomic.fetch_update(|x| x + 10);
assert_eq!(old, 0);
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_trait_atomic_number() {
fn test_number<T: AtomicNumber<Value = $value_type>>(atomic: &T) {
atomic.fetch_add(1);
atomic.fetch_add(5);
assert_eq!(atomic.load(), 6);
}
let atomic = <$atomic_type>::new(0);
test_number(&atomic);
}
#[test]
fn test_trait_atomic_compare_set_weak() {
fn test_atomic<T: Atomic<Value = $value_type>>(atomic: &T) {
atomic.store(10);
assert!(atomic.compare_set_weak(10, 20).is_ok());
assert_eq!(atomic.load(), 20);
}
let atomic = <$atomic_type>::new(0);
test_atomic(&atomic);
}
#[test]
fn test_trait_atomic_compare_exchange_weak() {
fn test_atomic<T: Atomic<Value = $value_type>>(atomic: &T) {
atomic.store(10);
let prev = atomic.compare_exchange_weak(10, 20);
assert_eq!(prev, 10);
assert_eq!(atomic.load(), 20);
}
let atomic = <$atomic_type>::new(0);
test_atomic(&atomic);
}
#[test]
fn test_trait_atomic_integer_fetch_sub() {
fn test_integer<T: AtomicNumber<Value = $value_type>>(atomic: &T) {
atomic.store(100);
let old = atomic.fetch_sub(30);
assert_eq!(old, 100);
assert_eq!(atomic.load(), 70);
}
let atomic = <$atomic_type>::new(0);
test_integer(&atomic);
}
#[test]
fn test_trait_atomic_integer_fetch_mul() {
fn test_integer<T: AtomicNumber<Value = $value_type>>(atomic: &T) {
atomic.store(5);
let old = atomic.fetch_mul(3);
assert_eq!(old, 5);
assert_eq!(atomic.load(), 15);
}
let atomic = <$atomic_type>::new(0);
test_integer(&atomic);
}
#[test]
fn test_trait_atomic_integer_fetch_div() {
fn test_integer<T: AtomicNumber<Value = $value_type>>(atomic: &T) {
atomic.store(20);
let old = atomic.fetch_div(4);
assert_eq!(old, 20);
assert_eq!(atomic.load(), 5);
}
let atomic = <$atomic_type>::new(0);
test_integer(&atomic);
}
#[test]
fn test_debug_display() {
let atomic = <$atomic_type>::new(42);
let debug_str = format!("{:?}", atomic);
assert!(debug_str.contains("42"));
let display_str = format!("{}", atomic);
assert_eq!(display_str, "42");
}
#[test]
fn test_inner_operations() {
use std::sync::atomic::Ordering;
let atomic = <$atomic_type>::new(10);
atomic.inner().store(100, Ordering::Relaxed);
assert_eq!(atomic.inner().load(Ordering::Relaxed), 100);
let old = atomic.inner().fetch_add(5, Ordering::Relaxed);
assert_eq!(old, 100);
assert_eq!(atomic.load(), 105);
}
#[test]
fn test_compare_and_set_weak_success() {
let atomic = <$atomic_type>::new(10);
assert!(atomic.compare_set_weak(10, 20).is_ok());
assert_eq!(atomic.load(), 20);
}
#[test]
fn test_compare_and_exchange_weak_success() {
let atomic = <$atomic_type>::new(10);
let prev = atomic.compare_and_exchange_weak(10, 20);
assert_eq!(prev, 10);
assert_eq!(atomic.load(), 20);
}
#[test]
fn test_get_and_accumulate_multiply() {
let atomic = <$atomic_type>::new(2);
let old = atomic.fetch_accumulate(3, |a, b| a.wrapping_mul(b));
assert_eq!(old, 2);
assert_eq!(atomic.load(), 6);
}
#[test]
fn test_max_with_smaller_value() {
let atomic = <$atomic_type>::new(50);
atomic.fetch_max(30);
assert_eq!(atomic.load(), 50);
}
#[test]
fn test_min_with_larger_value() {
let atomic = <$atomic_type>::new(50);
atomic.fetch_min(80);
assert_eq!(atomic.load(), 50);
}
#[test]
fn test_bitwise_combinations() {
let atomic = <$atomic_type>::new(0b1111);
atomic.fetch_and(0b1100);
assert_eq!(atomic.load(), 0b1100);
atomic.fetch_or(0b0011);
assert_eq!(atomic.load(), 0b1111);
atomic.fetch_xor(0b0101);
assert_eq!(atomic.load(), 0b1010);
}
#[test]
fn test_wrapping_decrement_from_one() {
let atomic = <$atomic_type>::new(1);
atomic.fetch_dec();
assert_eq!(atomic.load(), 0);
atomic.fetch_add(1);
assert_eq!(atomic.load(), 1);
}
#[test]
fn test_get_and_update_complex() {
let atomic = <$atomic_type>::new(10);
let old = atomic.fetch_update(|x| x.wrapping_mul(2).wrapping_add(5));
assert_eq!(old, 10);
assert_eq!(atomic.load(), 25);
}
#[test]
fn test_compare_and_set_failure_path() {
let atomic = <$atomic_type>::new(10);
match atomic.compare_set(5, 15) {
Ok(_) => panic!("Should have failed"),
Err(actual) => assert_eq!(actual, 10),
}
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_compare_and_exchange_failure_path() {
let atomic = <$atomic_type>::new(10);
let prev = atomic.compare_exchange(5, 15);
assert_eq!(prev, 10);
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_compare_and_set_weak_failure_path() {
let atomic = <$atomic_type>::new(10);
match atomic.compare_set_weak(5, 15) {
Ok(_) => panic!("Should have failed"),
Err(actual) => assert_eq!(actual, 10),
}
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_compare_and_exchange_weak_failure_path() {
let atomic = <$atomic_type>::new(10);
let prev = atomic.compare_and_exchange_weak(5, 15);
assert_eq!(prev, 10);
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_compare_set_weak_multiple_attempts() {
let atomic = <$atomic_type>::new(0);
for i in 0..100 {
let mut current = atomic.load();
loop {
match atomic.compare_set_weak(current, i) {
Ok(_) => break,
Err(actual) => current = actual,
}
}
}
assert_eq!(atomic.load(), 99);
}
#[test]
fn test_compare_exchange_weak_multiple_attempts() {
let atomic = <$atomic_type>::new(0);
for i in 0..100 {
let mut current = atomic.load();
loop {
let prev = atomic.compare_and_exchange_weak(current, i);
if prev == current {
break;
}
current = prev;
}
}
assert_eq!(atomic.load(), 99);
}
#[test]
fn test_compare_set_weak_with_zero() {
let atomic = <$atomic_type>::new(0);
assert!(atomic.compare_set_weak(0, 42).is_ok());
assert_eq!(atomic.load(), 42);
}
#[test]
fn test_compare_exchange_weak_with_zero() {
let atomic = <$atomic_type>::new(0);
let prev = atomic.compare_and_exchange_weak(0, 42);
assert_eq!(prev, 0);
assert_eq!(atomic.load(), 42);
}
#[test]
fn test_inner_compare_exchange_failure() {
use std::sync::atomic::Ordering;
let atomic = <$atomic_type>::new(10);
let result =
atomic
.inner()
.compare_exchange(5, 15, Ordering::AcqRel, Ordering::Acquire);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), 10);
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_inner_compare_exchange_weak_failure() {
use std::sync::atomic::Ordering;
let atomic = <$atomic_type>::new(10);
let result = atomic.inner().compare_exchange_weak(
5,
15,
Ordering::AcqRel,
Ordering::Acquire,
);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), 10);
assert_eq!(atomic.load(), 10);
}
#[test]
fn test_inner_fetch_operations_all() {
use std::sync::atomic::Ordering;
let atomic = <$atomic_type>::new(10);
let old = atomic.inner().fetch_sub(3, Ordering::Relaxed);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 7);
atomic.store(0b1111);
let old = atomic.inner().fetch_and(0b1100, Ordering::Relaxed);
assert_eq!(old, 0b1111);
assert_eq!(atomic.load(), 0b1100);
let old = atomic.inner().fetch_or(0b0011, Ordering::Relaxed);
assert_eq!(old, 0b1100);
assert_eq!(atomic.load(), 0b1111);
let old = atomic.inner().fetch_xor(0b0101, Ordering::Relaxed);
assert_eq!(old, 0b1111);
assert_eq!(atomic.load(), 0b1010);
}
#[test]
fn test_inner_fetch_max_min() {
use std::sync::atomic::Ordering;
let atomic = <$atomic_type>::new(10);
let old = atomic.inner().fetch_max(20, Ordering::Relaxed);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 20);
let old = atomic.inner().fetch_max(15, Ordering::Relaxed);
assert_eq!(old, 20);
assert_eq!(atomic.load(), 20);
let old = atomic.inner().fetch_min(5, Ordering::Relaxed);
assert_eq!(old, 20);
assert_eq!(atomic.load(), 5);
let old = atomic.inner().fetch_min(10, Ordering::Relaxed);
assert_eq!(old, 5);
assert_eq!(atomic.load(), 5);
}
#[test]
fn test_get_and_accumulate_divide() {
let atomic = <$atomic_type>::new(20);
let old = atomic.fetch_accumulate(4, |a, b| if b != 0 { a / b } else { a });
assert_eq!(old, 20);
assert_eq!(atomic.load(), 5);
}
#[test]
fn test_compare_and_exchange_success_path() {
let atomic = <$atomic_type>::new(10);
let prev = atomic.compare_exchange(10, 15);
assert_eq!(prev, 10);
assert_eq!(atomic.load(), 15);
}
#[test]
fn test_compare_and_exchange_weak_success_path() {
let atomic = <$atomic_type>::new(10);
let prev = atomic.compare_and_exchange_weak(10, 15);
assert_eq!(prev, 10);
assert_eq!(atomic.load(), 15);
}
#[test]
fn test_inner_compare_exchange_success() {
use std::sync::atomic::Ordering;
let atomic = <$atomic_type>::new(10);
let result =
atomic
.inner()
.compare_exchange(10, 15, Ordering::AcqRel, Ordering::Acquire);
assert!(result.is_ok());
assert_eq!(result.unwrap(), 10);
assert_eq!(atomic.load(), 15);
}
#[test]
fn test_inner_compare_exchange_weak_success() {
use std::sync::atomic::Ordering;
let atomic = <$atomic_type>::new(10);
let result = atomic.inner().compare_exchange_weak(
10,
15,
Ordering::AcqRel,
Ordering::Acquire,
);
assert!(result.is_ok());
assert_eq!(result.unwrap(), 10);
assert_eq!(atomic.load(), 15);
}
}
};
}