1use std::future::Future;
5use std::pin::Pin;
6#[cfg(feature = "test-util")]
7use std::sync::Arc;
8#[cfg(feature = "test-util")]
9use std::sync::atomic::{AtomicI64, Ordering};
10use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
11
12pub trait Clock: Send + Sync + 'static {
15 fn unix_secs(&self) -> i64;
17 fn unix_millis(&self) -> i64;
19 fn instant(&self) -> Instant;
21 fn sleep(&self, d: Duration) -> Pin<Box<dyn Future<Output = ()> + Send>>;
23}
24
25#[derive(Debug, Clone, Copy, Default)]
27pub struct SystemClock;
28
29impl Clock for SystemClock {
30 fn unix_secs(&self) -> i64 {
31 SystemTime::now()
32 .duration_since(UNIX_EPOCH)
33 .map_or(0, |d| i64::try_from(d.as_secs()).unwrap_or(i64::MAX))
34 }
35
36 fn unix_millis(&self) -> i64 {
37 SystemTime::now()
38 .duration_since(UNIX_EPOCH)
39 .map_or(0, |d| i64::try_from(d.as_millis()).unwrap_or(i64::MAX))
40 }
41
42 fn instant(&self) -> Instant {
43 Instant::now()
44 }
45
46 fn sleep(&self, d: Duration) -> Pin<Box<dyn Future<Output = ()> + Send>> {
47 Box::pin(tokio::time::sleep(d))
48 }
49}
50
51#[cfg(feature = "test-util")]
53#[derive(Debug, Clone)]
54pub struct ManualClock(Arc<ManualInner>);
55
56#[cfg(feature = "test-util")]
57#[derive(Debug)]
58struct ManualInner {
59 nanos: AtomicI64,
61 start_nanos: i64,
62 base: Instant,
63}
64
65#[cfg(feature = "test-util")]
66impl ManualClock {
67 #[must_use]
69 pub fn new(unix_secs: i64) -> ManualClock {
70 let nanos = unix_secs.saturating_mul(1_000_000_000);
71 ManualClock(Arc::new(ManualInner {
72 nanos: AtomicI64::new(nanos),
73 start_nanos: nanos,
74 base: Instant::now(),
75 }))
76 }
77
78 pub fn set(&self, unix_secs: i64) {
80 self.0
81 .nanos
82 .store(unix_secs.saturating_mul(1_000_000_000), Ordering::SeqCst);
83 }
84
85 pub fn advance(&self, secs: i64) {
87 self.0
88 .nanos
89 .fetch_add(secs.saturating_mul(1_000_000_000), Ordering::SeqCst);
90 }
91
92 pub fn advance_by(&self, d: Duration) {
94 self.0.nanos.fetch_add(
95 i64::try_from(d.as_nanos()).unwrap_or(i64::MAX),
96 Ordering::SeqCst,
97 );
98 }
99}
100
101#[cfg(feature = "test-util")]
102impl Default for ManualClock {
103 fn default() -> Self {
104 Self::new(0)
105 }
106}
107
108#[cfg(feature = "test-util")]
109impl Clock for ManualClock {
110 fn unix_secs(&self) -> i64 {
111 self.0
112 .nanos
113 .load(Ordering::SeqCst)
114 .div_euclid(1_000_000_000)
115 }
116
117 fn unix_millis(&self) -> i64 {
118 self.0.nanos.load(Ordering::SeqCst).div_euclid(1_000_000)
119 }
120
121 fn instant(&self) -> Instant {
122 let elapsed = self.0.nanos.load(Ordering::SeqCst) - self.0.start_nanos;
123 if elapsed >= 0 {
124 self.0.base + Duration::from_nanos(elapsed.unsigned_abs())
125 } else {
126 self.0
127 .base
128 .checked_sub(Duration::from_nanos(elapsed.unsigned_abs()))
129 .unwrap_or(self.0.base)
130 }
131 }
132
133 fn sleep(&self, _: Duration) -> Pin<Box<dyn Future<Output = ()> + Send>> {
134 Box::pin(std::future::ready(()))
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn system_clock_is_plausible_and_monotonic() {
144 let c = SystemClock;
145 assert!(c.unix_secs() > 1_700_000_000);
146 assert!(c.unix_millis() / 1000 >= c.unix_secs() - 1);
147 let a = c.instant();
148 assert!(c.instant() >= a);
149 }
150
151 #[tokio::test]
152 async fn system_clock_sleeps() {
153 let t = Instant::now();
154 SystemClock.sleep(Duration::from_millis(10)).await;
155 assert!(t.elapsed() >= Duration::from_millis(9));
156 }
157
158 #[cfg(feature = "test-util")]
159 #[tokio::test]
160 async fn manual_clock_moves_only_when_told_and_clones_share_time() {
161 let c = ManualClock::new(1_000);
162 let twin = c.clone();
163 let t0 = c.instant();
164 assert_eq!((c.unix_secs(), c.unix_millis()), (1_000, 1_000_000));
165 twin.advance(5);
166 assert_eq!(c.unix_secs(), 1_005);
167 assert_eq!(c.instant() - t0, Duration::from_secs(5));
168 c.advance_by(Duration::from_millis(1_500));
169 assert_eq!(twin.unix_millis(), 1_006_500);
170 assert_eq!(twin.unix_secs(), 1_006);
171 c.set(10);
172 assert_eq!(twin.unix_secs(), 10);
173 assert!(c.instant() < t0);
174 c.sleep(Duration::from_secs(3600)).await;
175 assert_eq!(ManualClock::default().unix_secs(), 0);
176 }
177}