use std::sync::Mutex;
use std::sync::PoisonError;
use std::time::{Duration, Instant};
pub trait Clock: Send + Sync + 'static {
fn now(&self) -> Instant;
}
#[derive(Clone, Copy, Debug, Default)]
pub struct MonotonicClock;
#[must_use]
pub fn monotonic_micros() -> u64 {
crate::sys::monotonic_micros()
}
impl Clock for MonotonicClock {
#[inline]
fn now(&self) -> Instant {
Instant::now()
}
}
#[derive(Debug)]
pub struct ManualClock {
now: Mutex<Instant>,
}
impl ManualClock {
#[must_use]
pub fn new() -> ManualClock {
ManualClock {
now: Mutex::new(Instant::now()),
}
}
pub fn advance(&self, by: Duration) {
let mut now = self.now.lock().unwrap_or_else(PoisonError::into_inner);
*now = now.checked_add(by).unwrap_or(*now);
}
pub fn set(&self, at: Instant) {
let mut now = self.now.lock().unwrap_or_else(PoisonError::into_inner);
if at > *now {
*now = at;
}
}
}
impl Default for ManualClock {
fn default() -> ManualClock {
ManualClock::new()
}
}
impl Clock for ManualClock {
fn now(&self) -> Instant {
*self.now.lock().unwrap_or_else(PoisonError::into_inner)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_manual_clock_frozen_until_advanced() {
let c = ManualClock::new();
let a = c.now();
std::thread::sleep(Duration::from_millis(2));
assert_eq!(c.now(), a);
c.advance(Duration::from_millis(5));
assert_eq!(c.now(), a + Duration::from_millis(5));
}
#[test]
fn test_manual_clock_set_forward_only() {
let c = ManualClock::new();
let a = c.now();
c.set(a + Duration::from_secs(3));
c.set(a);
assert_eq!(c.now(), a + Duration::from_secs(3));
}
}