use std::sync::Arc;
use std::sync::atomic::{AtomicI64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
pub trait Clock: Send + Sync + std::fmt::Debug {
fn now_ms(&self) -> i64;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct SystemClock;
impl Clock for SystemClock {
fn now_ms(&self) -> i64 {
let dur = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default();
i64::try_from(dur.as_millis()).unwrap_or(i64::MAX)
}
}
#[derive(Debug, Clone)]
pub struct MockClock {
inner: Arc<AtomicI64>,
}
impl MockClock {
#[must_use]
pub fn new(start_ms: i64) -> Self {
Self {
inner: Arc::new(AtomicI64::new(start_ms)),
}
}
pub fn advance(&self, delta_ms: i64) {
self.inner.fetch_add(delta_ms, Ordering::SeqCst);
}
}
impl Clock for MockClock {
fn now_ms(&self) -> i64 {
self.inner.load(Ordering::SeqCst)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mock_advances() {
let c = MockClock::new(100);
assert_eq!(c.now_ms(), 100);
c.advance(42);
assert_eq!(c.now_ms(), 142);
}
#[test]
fn system_clock_is_positive() {
assert!(SystemClock.now_ms() > 0);
}
}