Skip to main content

ferrin_core/
clock.rs

1//! Wall-clock source for response timestamps.
2//!
3//! Injecting a [`Clock`] lets tests produce deterministic
4//! `response.timestamp` values without touching the system time.
5
6use std::fmt;
7use std::sync::Arc;
8
9use chrono::DateTime;
10use chrono::Utc;
11
12/// Provides the current wall-clock time.
13pub trait Clock: Send + Sync {
14    /// The current time.
15    fn now(&self) -> DateTime<Utc>;
16}
17
18impl<F> Clock for F
19where
20    F: Fn() -> DateTime<Utc> + Send + Sync,
21{
22    fn now(&self) -> DateTime<Utc> {
23        self()
24    }
25}
26
27impl<T: Clock + ?Sized> Clock for Arc<T> {
28    fn now(&self) -> DateTime<Utc> {
29        (**self).now()
30    }
31}
32
33impl fmt::Debug for dyn Clock {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        f.write_str("Clock(..)")
36    }
37}
38
39/// The system clock (`chrono::Utc::now`).
40#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
41pub struct SystemClock;
42
43impl Clock for SystemClock {
44    fn now(&self) -> DateTime<Utc> {
45        Utc::now()
46    }
47}
48
49/// A clock that always returns the same instant.
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub struct FixedClock(pub DateTime<Utc>);
52
53impl Clock for FixedClock {
54    fn now(&self) -> DateTime<Utc> {
55        self.0
56    }
57}
58
59/// Returns the system clock as a shared trait object.
60#[must_use]
61pub fn default_clock() -> Arc<dyn Clock> {
62    Arc::new(SystemClock)
63}