use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
use std::vec::Vec;
use crate::compat::Duration;
#[derive(Debug, Default)]
struct Inner {
now: Duration,
sleeps: Vec<Duration>,
}
#[derive(Clone, Debug, Default)]
pub struct VirtualClock {
inner: Arc<Mutex<Inner>>,
}
impl VirtualClock {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn now(&self) -> Duration {
self.lock().now
}
pub fn advance(&self, dur: Duration) {
let mut inner = self.lock();
inner.now = inner.now.saturating_add(dur);
}
pub fn clock(&self) -> impl Fn() -> Duration + Clone + Send + Sync + 'static {
let inner = Arc::clone(&self.inner);
move || lock(&inner).now
}
pub fn sync_sleep(&self) -> impl FnMut(Duration) + Send + 'static {
let inner = Arc::clone(&self.inner);
move |dur| record_sleep(&inner, dur)
}
pub fn async_sleep(
&self,
) -> impl Fn(Duration) -> core::future::Ready<()> + Clone + Send + Sync + 'static {
let inner = Arc::clone(&self.inner);
move |dur| {
record_sleep(&inner, dur);
core::future::ready(())
}
}
#[must_use]
pub fn sleeps(&self) -> Vec<Duration> {
self.lock().sleeps.clone()
}
fn lock(&self) -> MutexGuard<'_, Inner> {
lock(&self.inner)
}
}
fn lock(inner: &Arc<Mutex<Inner>>) -> MutexGuard<'_, Inner> {
inner.lock().unwrap_or_else(PoisonError::into_inner)
}
fn record_sleep(inner: &Arc<Mutex<Inner>>, dur: Duration) {
let mut inner = lock(inner);
inner.now = inner.now.saturating_add(dur);
inner.sleeps.push(dur);
}