use crate::UnixTime;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
pub trait Clock: Send + Sync {
fn now(&self) -> UnixTime;
}
#[derive(Debug, Clone, Copy)]
pub struct SystemClock;
impl Clock for SystemClock {
#[allow(clippy::cast_possible_wrap)]
fn now(&self) -> UnixTime {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs() as i64)
.unwrap_or(0)
}
}
#[derive(Debug, Default)]
pub struct TestClock {
t: std::sync::atomic::AtomicI64,
}
impl TestClock {
#[must_use]
pub fn at(t: UnixTime) -> Arc<Self> {
Arc::new(Self {
t: std::sync::atomic::AtomicI64::new(t),
})
}
pub fn advance(&self, secs: i64) {
self.t.fetch_add(secs, std::sync::atomic::Ordering::Relaxed);
}
pub fn set(&self, t: UnixTime) {
self.t.store(t, std::sync::atomic::Ordering::Relaxed);
}
}
impl Clock for TestClock {
fn now(&self) -> UnixTime {
self.t.load(std::sync::atomic::Ordering::Relaxed)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_clock_advances_monotonically() {
let c = TestClock::at(100);
assert_eq!(c.now(), 100);
c.advance(5);
assert_eq!(c.now(), 105);
c.set(42);
assert_eq!(c.now(), 42);
}
#[test]
fn system_clock_is_nonnegative_and_near_now() {
let c = SystemClock;
assert!(c.now() > 1_735_689_600);
}
}