use qubit_atomic::atomic::{
Atomic,
AtomicRef,
};
use std::sync::Arc;
use std::thread;
#[derive(Debug, Clone, PartialEq)]
struct TestData {
value: i32,
name: String,
}
#[test]
fn test_new() {
let data = Arc::new(TestData {
value: 42,
name: "test".to_string(),
});
let atomic = AtomicRef::new(data.clone());
assert_eq!(atomic.load().value, 42);
assert_eq!(atomic.load().name, "test");
}
#[test]
fn test_get_set() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1);
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
atomic.store(data2);
let current = atomic.load();
assert_eq!(current.value, 100);
assert_eq!(current.name, "second");
}
#[test]
fn test_swap() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let old = atomic.swap(data2);
assert_eq!(old.value, 42);
assert_eq!(old.name, "first");
assert_eq!(atomic.load().value, 100);
}
#[test]
fn test_compare_and_set_success() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let current = atomic.load();
assert!(atomic.compare_set(¤t, data2).is_ok());
assert_eq!(atomic.load().value, 100);
}
#[test]
fn test_compare_and_set_failure() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let wrong_ref = Arc::new(TestData {
value: 999,
name: "wrong".to_string(),
});
match atomic.compare_set(&wrong_ref, data2) {
Ok(_) => panic!("Should fail"),
Err(actual) => {
assert_eq!(actual.value, 42);
assert_eq!(actual.name, "first");
}
}
assert_eq!(atomic.load().value, 42);
}
#[test]
fn test_compare_and_exchange() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let current = atomic.load();
let prev = atomic.compare_exchange(current.clone(), data2);
assert!(Arc::ptr_eq(&prev, ¤t));
assert_eq!(atomic.load().value, 100);
}
#[test]
fn test_get_and_update() {
let data = Arc::new(TestData {
value: 42,
name: "test".to_string(),
});
let atomic = AtomicRef::new(data);
let old = atomic.fetch_update(|current| {
Arc::new(TestData {
value: current.value * 2,
name: format!("{}_updated", current.name),
})
});
assert_eq!(old.value, 42);
assert_eq!(old.name, "test");
assert_eq!(atomic.load().value, 84);
assert_eq!(atomic.load().name, "test_updated");
}
#[test]
fn test_concurrent_updates() {
let data = Arc::new(TestData {
value: 0,
name: "counter".to_string(),
});
let atomic = Arc::new(AtomicRef::new(data));
let mut handles = vec![];
for i in 0..10 {
let atomic = atomic.clone();
let handle = thread::spawn(move || {
atomic.fetch_update(|current| {
Arc::new(TestData {
value: current.value + 1,
name: format!("thread_{}", i),
})
});
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(atomic.load().value, 10);
}
#[test]
fn test_concurrent_cas() {
let data = Arc::new(0);
let atomic = Arc::new(AtomicRef::new(data));
let success_count = Arc::new(std::sync::atomic::AtomicUsize::new(0));
let mut handles = vec![];
for _ in 0..10 {
let atomic = atomic.clone();
let success_count = success_count.clone();
let handle = thread::spawn(move || {
let mut current = atomic.load();
loop {
let new = Arc::new(*current + 1);
match atomic.compare_set_weak(¤t, new) {
Ok(_) => {
success_count.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
break;
}
Err(actual) => current = actual,
}
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(*atomic.load(), 10);
assert_eq!(success_count.load(std::sync::atomic::Ordering::Relaxed), 10);
}
#[test]
fn test_clone() {
let data = Arc::new(TestData {
value: 42,
name: "test".to_string(),
});
let atomic1 = AtomicRef::new(data);
let atomic2 = atomic1.clone();
assert_eq!(atomic1.load().value, 42);
assert_eq!(atomic2.load().value, 42);
atomic1.store(Arc::new(TestData {
value: 100,
name: "updated".to_string(),
}));
assert_eq!(atomic1.load().value, 100);
assert_eq!(atomic2.load().value, 42);
}
#[test]
fn test_trait_atomic() {
fn test_atomic<T: Atomic<Value = Arc<i32>>>(atomic: &T) {
atomic.store(Arc::new(42));
assert_eq!(*atomic.load(), 42);
let old = atomic.swap(Arc::new(100));
assert_eq!(*old, 42);
}
let atomic = AtomicRef::new(Arc::new(0));
test_atomic(&atomic);
}
#[test]
fn test_trait_atomic_compare_set_weak() {
fn test_atomic<T: Atomic<Value = Arc<i32>>>(atomic: &T) {
atomic.store(Arc::new(10));
let current = atomic.load();
assert!(atomic.compare_set_weak(current, Arc::new(20)).is_ok());
assert_eq!(*atomic.load(), 20);
}
let atomic = AtomicRef::new(Arc::new(0));
test_atomic(&atomic);
}
#[test]
fn test_trait_atomic_compare_exchange() {
fn test_atomic<T: Atomic<Value = Arc<i32>>>(atomic: &T) {
atomic.store(Arc::new(10));
let current = atomic.load();
let prev = atomic.compare_exchange(current.clone(), Arc::new(20));
assert!(Arc::ptr_eq(&prev, ¤t) || *prev == 10);
assert_eq!(*atomic.load(), 20);
}
let atomic = AtomicRef::new(Arc::new(0));
test_atomic(&atomic);
}
#[test]
fn test_trait_atomic_compare_exchange_weak() {
fn test_atomic<T: Atomic<Value = Arc<i32>>>(atomic: &T) {
atomic.store(Arc::new(10));
let current = atomic.load();
let prev = atomic.compare_exchange_weak(current.clone(), Arc::new(20));
assert!(Arc::ptr_eq(&prev, ¤t) || *prev == 10);
assert_eq!(*atomic.load(), 20);
}
let atomic = AtomicRef::new(Arc::new(0));
test_atomic(&atomic);
}
#[test]
fn test_trait_atomic_fetch_update() {
fn test_atomic<T: Atomic<Value = Arc<i32>>>(atomic: &T) {
atomic.store(Arc::new(10));
let old = atomic.fetch_update(|x| Arc::new(*x * 2));
assert_eq!(*old, 10);
assert_eq!(*atomic.load(), 20);
}
let atomic = AtomicRef::new(Arc::new(0));
test_atomic(&atomic);
}
#[test]
fn test_debug_display() {
let data = Arc::new(42);
let atomic = AtomicRef::new(data);
let debug_str = format!("{:?}", atomic);
assert!(debug_str.contains("42"));
let display_str = format!("{}", atomic);
assert_eq!(display_str, "42");
}
#[test]
fn test_arc_reference_counting() {
let data = Arc::new(TestData {
value: 42,
name: "test".to_string(),
});
assert_eq!(Arc::strong_count(&data), 1);
let atomic = AtomicRef::new(data.clone());
assert_eq!(Arc::strong_count(&data), 2);
let retrieved = atomic.load();
assert_eq!(Arc::strong_count(&data), 3);
drop(retrieved);
assert_eq!(Arc::strong_count(&data), 2);
drop(atomic);
assert_eq!(Arc::strong_count(&data), 1);
}
#[test]
fn test_compare_and_set_weak_success() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let current = atomic.load();
assert!(atomic.compare_set_weak(¤t, data2).is_ok());
assert_eq!(atomic.load().value, 100);
}
#[test]
fn test_compare_and_set_weak_failure() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let wrong_ref = Arc::new(TestData {
value: 999,
name: "wrong".to_string(),
});
match atomic.compare_set_weak(&wrong_ref, data2) {
Ok(_) => panic!("Should fail"),
Err(actual) => {
assert_eq!(actual.value, 42);
assert_eq!(actual.name, "first");
}
}
}
#[test]
fn test_compare_and_exchange_weak() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let current = atomic.load();
let prev = atomic.compare_and_exchange_weak(¤t, data2);
assert!(Arc::ptr_eq(&prev, ¤t));
assert_eq!(atomic.load().value, 100);
}
#[test]
fn test_inner() {
use std::sync::atomic::Ordering;
let data = Arc::new(TestData {
value: 42,
name: "test".to_string(),
});
let atomic = AtomicRef::new(data.clone());
let ptr = atomic.inner().load(Ordering::Relaxed);
assert!(!ptr.is_null());
let new_data = Arc::new(TestData {
value: 100,
name: "new".to_string(),
});
atomic
.inner()
.store(Arc::into_raw(new_data.clone()) as *mut _, Ordering::Release);
let retrieved = atomic.load();
assert_eq!(retrieved.value, 100);
}
#[test]
fn test_new_with_primitive() {
let atomic = AtomicRef::new(Arc::new(42));
assert_eq!(*atomic.load(), 42);
}
#[test]
fn test_new_with_string() {
let atomic = AtomicRef::new(Arc::new("hello".to_string()));
assert_eq!(*atomic.load(), "hello");
}
#[test]
fn test_swap_same_value() {
let data = Arc::new(42);
let atomic = AtomicRef::new(data.clone());
let old = atomic.swap(data.clone());
assert_eq!(*old, 42);
assert_eq!(*atomic.load(), 42);
}
#[test]
fn test_concurrent_get() {
let data = Arc::new(TestData {
value: 42,
name: "shared".to_string(),
});
let atomic = Arc::new(AtomicRef::new(data));
let mut handles = vec![];
for _ in 0..10 {
let atomic = atomic.clone();
let handle = thread::spawn(move || {
for _ in 0..100 {
let value = atomic.load();
assert_eq!(value.value, 42);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn test_concurrent_swap() {
let data = Arc::new(0);
let atomic = Arc::new(AtomicRef::new(data));
let mut handles = vec![];
for i in 0..10 {
let atomic = atomic.clone();
let handle = thread::spawn(move || {
atomic.swap(Arc::new(i));
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let final_value = *atomic.load();
assert!(final_value < 10);
}
#[test]
fn test_update_with_closure() {
let data = Arc::new(10);
let atomic = AtomicRef::new(data);
let old = atomic.fetch_update(|current| Arc::new(**current * 2));
assert_eq!(*old, 10);
assert_eq!(*atomic.load(), 20);
let old2 = atomic.fetch_update(|current| Arc::new(**current + 5));
assert_eq!(*old2, 20); assert_eq!(*atomic.load(), 25); }
#[test]
fn test_compare_and_set_weak_in_loop() {
let data = Arc::new(0);
let atomic = AtomicRef::new(data);
let mut current = atomic.load();
for i in 0..10 {
loop {
let new_data = Arc::new(i + 1);
match atomic.compare_set_weak(¤t, new_data) {
Ok(_) => break,
Err(actual) => current = actual,
}
}
current = Arc::new(i + 1);
}
assert_eq!(*atomic.load(), 10);
}
#[test]
fn test_compare_and_exchange_weak_in_loop() {
let data = Arc::new(0);
let atomic = AtomicRef::new(data);
let mut current = atomic.load();
for i in 0..10 {
loop {
let new_data = Arc::new(i + 1);
let prev = atomic.compare_and_exchange_weak(¤t, new_data);
if Arc::ptr_eq(&prev, ¤t) {
break;
}
current = prev;
}
current = Arc::new(i + 1);
}
assert_eq!(*atomic.load(), 10);
}
#[test]
fn test_inner_compare_exchange() {
use std::sync::atomic::Ordering;
let data = Arc::new(42);
let atomic = AtomicRef::new(data.clone());
let current_ptr = atomic.inner().load(Ordering::Relaxed);
let new_data = Arc::new(100);
let new_ptr = Arc::into_raw(new_data.clone()) as *mut _;
let result =
atomic
.inner()
.compare_exchange(current_ptr, new_ptr, Ordering::AcqRel, Ordering::Acquire);
assert!(result.is_ok());
assert_eq!(*atomic.load(), 100);
}
#[test]
fn test_clone_independence() {
let data = Arc::new(TestData {
value: 42,
name: "test".to_string(),
});
let atomic1 = AtomicRef::new(data);
let atomic2 = atomic1.clone();
assert_eq!(atomic1.load().value, 42);
assert_eq!(atomic2.load().value, 42);
atomic1.store(Arc::new(TestData {
value: 100,
name: "new".to_string(),
}));
assert_eq!(atomic2.load().value, 42);
}
#[test]
fn test_display_simple() {
let atomic = AtomicRef::new(Arc::new(42));
let display_str = format!("{}", atomic);
assert_eq!(display_str, "42");
}
#[test]
fn test_debug_simple() {
let atomic = AtomicRef::new(Arc::new(42));
let debug_str = format!("{:?}", atomic);
assert!(debug_str.contains("42"));
}
#[test]
fn test_trait_atomic_comprehensive() {
fn test_atomic<T: Atomic<Value = Arc<i32>>>(atomic: &T) {
atomic.store(Arc::new(5));
assert_eq!(*atomic.load(), 5);
let old = atomic.swap(Arc::new(10));
assert_eq!(*old, 5);
let current = atomic.load();
assert!(atomic.compare_set(current.clone(), Arc::new(15)).is_ok());
let current2 = atomic.load();
let prev = atomic.compare_exchange(current2.clone(), Arc::new(20));
assert!(Arc::ptr_eq(&prev, ¤t2) || *prev == 15);
}
let atomic = AtomicRef::new(Arc::new(0));
test_atomic(&atomic);
}
#[test]
fn test_compare_and_set_same_value() {
let data = Arc::new(42);
let atomic = AtomicRef::new(data.clone());
let current = atomic.load();
assert!(atomic.compare_set(¤t, data.clone()).is_ok());
assert_eq!(*atomic.load(), 42);
}
#[test]
fn test_compare_and_exchange_same_value() {
let data = Arc::new(42);
let atomic = AtomicRef::new(data.clone());
let current = atomic.load();
let prev = atomic.compare_exchange(current.clone(), data.clone());
assert!(Arc::ptr_eq(&prev, ¤t));
}
#[test]
fn test_compare_and_set_failure_path() {
let data1 = Arc::new(42);
let data2 = Arc::new(100);
let wrong = Arc::new(999);
let atomic = AtomicRef::new(data1);
match atomic.compare_set(&wrong, data2) {
Ok(_) => panic!("Should have failed"),
Err(actual) => assert_eq!(*actual, 42),
}
assert_eq!(*atomic.load(), 42);
}
#[test]
fn test_compare_and_exchange_failure_path() {
let data1 = Arc::new(42);
let data2 = Arc::new(100);
let wrong = Arc::new(999);
let atomic = AtomicRef::new(data1);
let prev = atomic.compare_exchange(wrong.clone(), data2);
assert_eq!(*prev, 42);
assert_eq!(*atomic.load(), 42);
}
#[test]
fn test_compare_and_set_weak_failure_path() {
let data1 = Arc::new(42);
let data2 = Arc::new(100);
let wrong = Arc::new(999);
let atomic = AtomicRef::new(data1);
match atomic.compare_set_weak(&wrong, data2) {
Ok(_) => panic!("Should have failed"),
Err(actual) => assert_eq!(*actual, 42),
}
assert_eq!(*atomic.load(), 42);
}
#[test]
fn test_compare_and_exchange_weak_failure_path() {
let data1 = Arc::new(42);
let data2 = Arc::new(100);
let wrong = Arc::new(999);
let atomic = AtomicRef::new(data1);
let prev = atomic.compare_and_exchange_weak(&wrong, data2);
assert_eq!(*prev, 42);
assert_eq!(*atomic.load(), 42);
}
#[test]
fn test_inner_compare_exchange_failure() {
use std::sync::atomic::Ordering;
let data = Arc::new(42);
let atomic = AtomicRef::new(data.clone());
let wrong_ptr = std::ptr::null_mut();
let new_data = Arc::new(100);
let new_ptr = Arc::into_raw(new_data) as *mut _;
let result =
atomic
.inner()
.compare_exchange(wrong_ptr, new_ptr, Ordering::AcqRel, Ordering::Acquire);
assert!(result.is_err());
unsafe {
let _ = Arc::from_raw(new_ptr);
}
}
#[test]
fn test_inner_compare_exchange_weak_failure() {
use std::sync::atomic::Ordering;
let data = Arc::new(42);
let atomic = AtomicRef::new(data.clone());
let wrong_ptr = std::ptr::null_mut();
let new_data = Arc::new(100);
let new_ptr = Arc::into_raw(new_data) as *mut _;
let result = atomic.inner().compare_exchange_weak(
wrong_ptr,
new_ptr,
Ordering::AcqRel,
Ordering::Acquire,
);
assert!(result.is_err());
unsafe {
let _ = Arc::from_raw(new_ptr);
}
}
#[test]
fn test_compare_and_exchange_success_path() {
let data1 = Arc::new(42);
let atomic = AtomicRef::new(data1.clone());
let current = atomic.load();
let data2 = Arc::new(100);
let prev = atomic.compare_exchange(current.clone(), data2);
assert!(Arc::ptr_eq(&prev, ¤t));
assert_eq!(*atomic.load(), 100);
}
#[test]
fn test_compare_and_exchange_weak_success_path() {
let data1 = Arc::new(42);
let atomic = AtomicRef::new(data1.clone());
let current = atomic.load();
let data2 = Arc::new(100);
let prev = atomic.compare_and_exchange_weak(¤t, data2);
assert!(Arc::ptr_eq(&prev, ¤t));
assert_eq!(*atomic.load(), 100);
}
#[test]
fn test_concurrent_get_and_update_high_contention() {
let atomic = Arc::new(AtomicRef::new(Arc::new(0)));
let mut handles = vec![];
for _ in 0..20 {
let atomic = atomic.clone();
let handle = thread::spawn(move || {
for _ in 0..10 {
atomic.fetch_update(|current| Arc::new(**current + 1));
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(*atomic.load(), 200);
}
#[test]
fn test_direct_compare_and_exchange_success() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let current = atomic.load();
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let prev = atomic.compare_and_exchange(¤t, data2);
assert!(Arc::ptr_eq(&prev, ¤t));
assert_eq!(atomic.load().value, 100);
assert_eq!(atomic.load().name, "second");
}
#[test]
fn test_direct_compare_and_exchange_failure() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let wrong_ref = Arc::new(TestData {
value: 999,
name: "wrong".to_string(),
});
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let prev = atomic.compare_and_exchange(&wrong_ref, data2);
assert_eq!(prev.value, 42);
assert_eq!(prev.name, "first");
assert_eq!(atomic.load().value, 42);
}
#[test]
fn test_direct_compare_and_exchange_with_simple_type() {
let data1 = Arc::new(42);
let atomic = AtomicRef::new(data1.clone());
let current = atomic.load();
let data2 = Arc::new(100);
let prev = atomic.compare_and_exchange(¤t, data2);
assert!(Arc::ptr_eq(&prev, ¤t));
assert_eq!(*atomic.load(), 100);
}
#[test]
fn test_direct_compare_and_exchange_weak_success() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let current = atomic.load();
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let prev = atomic.compare_and_exchange_weak(¤t, data2);
assert!(Arc::ptr_eq(&prev, ¤t));
assert_eq!(atomic.load().value, 100);
}
#[test]
fn test_direct_compare_and_exchange_weak_failure() {
let data1 = Arc::new(TestData {
value: 42,
name: "first".to_string(),
});
let atomic = AtomicRef::new(data1.clone());
let wrong_ref = Arc::new(TestData {
value: 999,
name: "wrong".to_string(),
});
let data2 = Arc::new(TestData {
value: 100,
name: "second".to_string(),
});
let prev = atomic.compare_and_exchange_weak(&wrong_ref, data2);
assert_eq!(prev.value, 42);
assert_eq!(prev.name, "first");
assert_eq!(atomic.load().value, 42);
}
#[test]
fn test_direct_compare_and_exchange_weak_in_loop() {
let data = Arc::new(TestData {
value: 0,
name: "counter".to_string(),
});
let atomic = AtomicRef::new(data);
let mut current = atomic.load();
loop {
let new_data = Arc::new(TestData {
value: current.value + 1,
name: "updated".to_string(),
});
let prev = atomic.compare_and_exchange_weak(¤t, new_data);
if Arc::ptr_eq(&prev, ¤t) {
break;
}
current = prev;
}
assert_eq!(atomic.load().value, 1);
assert_eq!(atomic.load().name, "updated");
}