use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug)]
pub struct Tracked {
pub id: u64,
live: Arc<Counts>,
}
#[derive(Default, Debug)]
pub struct Counts {
pub made: AtomicUsize,
pub dropped: AtomicUsize,
}
impl Counts {
pub fn new() -> Arc<Self> {
Arc::new(Self::default())
}
pub fn value(self: &Arc<Self>, id: u64) -> Tracked {
self.made.fetch_add(1, Ordering::Relaxed);
Tracked {
id,
live: Arc::clone(self),
}
}
pub fn balanced(&self) -> bool {
self.made.load(Ordering::SeqCst) == self.dropped.load(Ordering::SeqCst)
}
}
impl Clone for Tracked {
fn clone(&self) -> Self {
self.live.value(self.id)
}
}
impl PartialEq for Tracked {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Drop for Tracked {
fn drop(&mut self) {
self.live.dropped.fetch_add(1, Ordering::Relaxed);
}
}
pub fn settle(counts: &Counts) {
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(10);
while !counts.balanced() && std::time::Instant::now() < deadline {
for _ in 0..64 {
kovan::flush();
}
}
}
pub fn serial() -> std::sync::MutexGuard<'static, ()> {
static SERIAL: std::sync::Mutex<()> = std::sync::Mutex::new(());
SERIAL
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
}
#[derive(Clone)]
pub struct Rng(u64);
impl Rng {
pub fn new(seed: u64) -> Self {
Self(seed.wrapping_mul(0x9E37_79B9_7F4A_7C15) | 1)
}
pub fn next(&mut self) -> u64 {
let mut x = self.0;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
self.0 = x;
x.wrapping_mul(0x2545_F491_4F6C_DD1D)
}
pub fn below(&mut self, n: u64) -> u64 {
self.next() % n
}
}
pub fn scaled(default: usize) -> usize {
std::env::var("KOVAN_STRESS_SCALE")
.ok()
.and_then(|s| s.parse::<usize>().ok())
.map_or(default, |m| default * m.max(1))
}