mod condition_check_reactor;
pub mod network;
mod test_rng;
use std::{
collections::HashSet,
fmt::Debug,
sync::atomic::{AtomicU16, Ordering},
};
use serde::{de::DeserializeOwned, Serialize};
use crate::logging;
pub(crate) use condition_check_reactor::ConditionCheckReactor;
pub(crate) use test_rng::TestRng;
const PORT_LOWER_BOUND: u16 = 10_000;
pub fn bincode_roundtrip<T: Serialize + DeserializeOwned + Eq + Debug>(value: &T) {
let serialized = bincode::serialize(value).unwrap();
let deserialized = bincode::deserialize(serialized.as_slice()).unwrap();
assert_eq!(*value, deserialized);
}
#[allow(clippy::assertions_on_constants)]
pub(crate) fn unused_port_on_localhost() -> u16 {
const PRIME: u16 = 54101;
const GENERATOR: u16 = 35892;
assert!(PORT_LOWER_BOUND + PRIME + 10 < u16::MAX);
static RNG_STATE: AtomicU16 = AtomicU16::new(GENERATOR);
for _ in 0..10_000 {
if let Ok(fresh_port) =
RNG_STATE.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| {
let new_value = (state as u32 + GENERATOR as u32) % (PRIME as u32);
Some(new_value as u16 + PORT_LOWER_BOUND)
})
{
return fresh_port;
}
}
panic!("could not generate random new port after 10_000 tries");
}
pub(crate) fn init_logging() {
logging::init()
.ok();
}
#[test]
fn test_random_port_gen() {
const NUM_ROUNDS: usize = 40_000;
let values: HashSet<_> = (0..NUM_ROUNDS)
.map(|_| {
let port = unused_port_on_localhost();
assert!(port >= PORT_LOWER_BOUND);
port
})
.collect();
assert_eq!(values.len(), NUM_ROUNDS);
}