use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
pub trait Clock: Send + Sync + std::fmt::Debug {
fn now(&self) -> u64;
}
pub type SharedClock = Arc<dyn Clock + Send + Sync>;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct SystemClock;
impl Clock for SystemClock {
fn now(&self) -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0)
}
}
#[derive(Clone, Debug)]
pub struct MockClock {
now: Arc<AtomicU64>,
}
impl MockClock {
pub fn new(now: u64) -> Self {
Self {
now: Arc::new(AtomicU64::new(now)),
}
}
pub fn set_now(&self, now: u64) {
self.now.store(now, Ordering::Relaxed);
}
pub fn advance(&self, secs: u64) {
self.now.fetch_add(secs, Ordering::Relaxed);
}
pub fn peek(&self) -> u64 {
self.now.load(Ordering::Relaxed)
}
}
impl Clock for MockClock {
fn now(&self) -> u64 {
self.peek()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mock_clock_set_and_advance() {
let c = MockClock::new(1000);
assert_eq!(c.peek(), 1000);
c.advance(50);
assert_eq!(c.peek(), 1050);
c.set_now(2000);
assert_eq!(c.peek(), 2000);
let shared: SharedClock = Arc::new(c.clone());
assert_eq!(shared.now(), 2000);
}
#[test]
fn mock_clock_clone_shares_state() {
let c = MockClock::new(1);
let d = c.clone();
c.set_now(99);
assert_eq!(d.peek(), 99);
}
#[test]
fn system_clock_returns_unix_seconds() {
let now = SystemClock.now();
assert!(now > 1_700_000_000, "SystemClock 应返回 Unix 秒,得到 {now}");
}
}