use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
pub trait Clock: Send + Sync + 'static {
fn now_unix_secs(&self) -> u64;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SystemClock;
impl Clock for SystemClock {
fn now_unix_secs(&self) -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0)
}
}
#[derive(Debug, Clone)]
pub struct FixedClock(Arc<AtomicU64>);
impl FixedClock {
pub fn new(secs: u64) -> Self {
FixedClock(Arc::new(AtomicU64::new(secs)))
}
pub fn advance(&self, secs: u64) {
self.0.fetch_add(secs, Ordering::SeqCst);
}
pub fn set(&self, secs: u64) {
self.0.store(secs, Ordering::SeqCst);
}
}
impl Clock for FixedClock {
fn now_unix_secs(&self) -> u64 {
self.0.load(Ordering::SeqCst)
}
}
#[cfg(all(test, not(target_arch = "wasm32")))]
mod tests {
use super::*;
#[test]
fn fixed_clock_returns_injected_time() {
let clock = FixedClock::new(1_700_000_000);
assert_eq!(clock.now_unix_secs(), 1_700_000_000);
}
#[test]
fn fixed_clock_can_advance() {
let clock = FixedClock::new(100);
clock.advance(50);
assert_eq!(clock.now_unix_secs(), 150);
}
#[test]
fn fixed_clock_set_overwrites() {
let clock = FixedClock::new(100);
clock.set(999);
assert_eq!(clock.now_unix_secs(), 999);
}
#[test]
fn system_clock_is_after_2020() {
let clock = SystemClock;
assert!(clock.now_unix_secs() > 1_577_836_800);
}
}