use std::sync::Arc;
use std::time::Instant;
pub trait RuntimeClock: Send + Sync {
fn now(&self) -> Instant;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SystemClock;
impl RuntimeClock for SystemClock {
fn now(&self) -> Instant {
Instant::now()
}
}
#[derive(Debug, Clone, Copy)]
pub struct FixedClock {
instant: Instant,
}
impl FixedClock {
pub fn new(instant: Instant) -> Self {
Self { instant }
}
}
impl RuntimeClock for FixedClock {
fn now(&self) -> Instant {
self.instant
}
}
#[derive(Clone)]
pub struct ClockHandle(Arc<dyn RuntimeClock + Send + Sync>);
impl std::fmt::Debug for ClockHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("ClockHandle(<dyn RuntimeClock>)")
}
}
impl ClockHandle {
pub fn new(clock: Arc<dyn RuntimeClock + Send + Sync>) -> Self {
Self(clock)
}
pub fn system() -> Self {
Self(Arc::new(SystemClock))
}
}
impl RuntimeClock for ClockHandle {
fn now(&self) -> Instant {
self.0.now()
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
use crate::fact::{FactId, IoType};
use crate::state::ReactorState;
use std::time::Duration;
#[test]
fn fixed_clock_returns_constructed_instant() {
let base = Instant::now();
let clock = FixedClock::new(base);
assert_eq!(clock.now(), base);
std::thread::sleep(Duration::from_millis(5));
assert_eq!(clock.now(), base);
}
#[test]
fn system_clock_monotonic() {
let clock = SystemClock;
let a = clock.now();
let b = clock.now();
assert!(b >= a);
}
#[test]
fn fixed_clock_drives_deterministic_timeout_scan() {
let mut state = ReactorState::new();
let base = Instant::now();
let clock = FixedClock::new(base);
state.register_io_request_at(FactId(1), IoType::new("t"), base - Duration::from_secs(40));
state.register_io_request_at(FactId(2), IoType::new("t"), base - Duration::from_secs(70));
let (warn_ids, error_ids) = state.scan_io_timeouts_at(
clock.now(),
Duration::from_secs(30),
Duration::from_secs(60),
);
assert_eq!(warn_ids, vec![FactId(1)]);
assert_eq!(error_ids, vec![FactId(2)]);
}
#[test]
fn clock_handle_forwards_to_inner_clock() {
let base = Instant::now();
let handle = ClockHandle::new(Arc::new(FixedClock::new(base)));
assert_eq!(handle.now(), base);
assert!(
ClockHandle::system().now() <= Instant::now() + Duration::from_secs(1),
"SystemClock 必须返回不晚于当前时刻的时间戳"
);
}
}