1use std::time::Instant;
2
3pub trait SystemClock: Send + Sync {
4 /// Returns the current date and time in UTC.
5 fn utc_now(&self) -> Instant;
6}
7
8pub struct RealSystemClock;
9
10impl SystemClock for RealSystemClock {
11 fn utc_now(&self) -> Instant {
12 Instant::now()
13 }
14}
15
16#[cfg(any(test, feature = "test-support"))]
17pub struct FakeSystemClockState {
18 now: Instant,
19}
20
21#[cfg(any(test, feature = "test-support"))]
22pub struct FakeSystemClock {
23 // Use an unfair lock to ensure tests are deterministic.
24 state: parking_lot::Mutex<FakeSystemClockState>,
25}
26
27#[cfg(any(test, feature = "test-support"))]
28impl FakeSystemClock {
29 pub fn new() -> Self {
30 let state = FakeSystemClockState {
31 now: Instant::now(),
32 };
33
34 Self {
35 state: parking_lot::Mutex::new(state),
36 }
37 }
38
39 pub fn set_now(&self, now: Instant) {
40 self.state.lock().now = now;
41 }
42
43 pub fn advance(&self, duration: std::time::Duration) {
44 self.state.lock().now += duration;
45 }
46}
47
48#[cfg(any(test, feature = "test-support"))]
49impl SystemClock for FakeSystemClock {
50 fn utc_now(&self) -> Instant {
51 self.state.lock().now
52 }
53}