use orx_concurrent_option::*;
use std::{sync::atomic::Ordering, time::Duration};
use test_case::test_matrix;
#[cfg(not(miri))]
const N: usize = 100;
#[cfg(miri)]
const N: usize = 15;
#[test_matrix(
[2, 4, 8, 16],
[false, true],
[Ordering::SeqCst, Ordering::Acquire]
)]
fn concurrent_initialize_if_none_single_writer(
num_readers: usize,
do_sleep: bool,
read_order: Ordering,
) {
let maybe = ConcurrentOption::<String>::none();
let maybe_ref = &maybe;
std::thread::scope(|s| {
for _ in 0..(num_readers / 2) {
s.spawn(move || read(do_sleep, maybe_ref, read_order));
}
s.spawn(move || write_single(do_sleep, maybe_ref));
for _ in 0..(num_readers / 2) {
s.spawn(move || read(do_sleep, maybe_ref, read_order));
}
});
}
#[test_matrix(
[4, 8],
[2, 4, 8, 16],
[false, true],
[Ordering::SeqCst, Ordering::Acquire]
)]
fn concurrent_initialize_if_none_multiple_writer(
num_writers: usize,
num_readers: usize,
do_sleep: bool,
read_order: Ordering,
) {
let maybe = ConcurrentOption::<String>::none();
let maybe_ref = &maybe;
std::thread::scope(|s| {
for _ in 0..(num_writers / 2) {
s.spawn(move || write_multi(do_sleep, maybe_ref));
}
for _ in 0..num_readers {
s.spawn(move || read(do_sleep, maybe_ref, read_order));
}
for _ in 0..(num_writers / 2) {
s.spawn(move || write_multi(do_sleep, maybe_ref));
}
});
}
fn read(do_sleep: bool, maybe_ref: &ConcurrentOption<String>, read_order: Ordering) {
for _ in 0..N {
sleep(do_sleep);
let read = unsafe { maybe_ref.as_ref_with_order(read_order) };
let is_none = read.is_none();
let is_seven = read == Some(&7.to_string());
assert!(is_none || is_seven);
}
}
fn write_single(do_sleep: bool, maybe_ref: &ConcurrentOption<String>) {
for i in 0..N {
sleep(do_sleep);
match i {
x if x == N / 3 => {
let inserted = maybe_ref.initialize_if_none(7.to_string());
assert!(inserted);
}
x if x == 2 * N / 3 => {
let inserted = maybe_ref.initialize_if_none(111.to_string());
assert!(!inserted);
}
_ => {}
}
}
}
fn write_multi(do_sleep: bool, maybe_ref: &ConcurrentOption<String>) {
for i in 0..N {
sleep(do_sleep);
match i {
x if x == N / 3 || x == 2 * N / 3 => {
let _ = maybe_ref.initialize_if_none(7.to_string());
}
_ => {}
}
}
}
fn sleep(do_sleep: bool) {
if do_sleep {
let duration = Duration::from_millis(24);
std::thread::sleep(duration);
}
}