1use std::sync::atomic::{AtomicI64, Ordering};
17use std::time::{Duration, SystemTime, UNIX_EPOCH};
18
19pub const TICKS_PER_SECOND: i64 = 10_000_000;
24
25const NANOS_PER_TICK: i64 = 100;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
33pub struct Timestamp(i64);
34
35impl Timestamp {
36 pub const MIN: Timestamp = Timestamp(i64::MIN);
38 pub const MAX: Timestamp = Timestamp(i64::MAX);
40
41 #[must_use]
43 pub const fn from_ticks(ticks: i64) -> Self {
44 Self(ticks)
45 }
46
47 #[must_use]
49 pub const fn ticks(self) -> i64 {
50 self.0
51 }
52
53 #[must_use]
56 pub fn saturating_add(self, duration: Duration) -> Self {
57 Self(self.0.saturating_add(duration_to_ticks(duration)))
58 }
59
60 #[must_use]
63 pub fn saturating_duration_since(self, earlier: Timestamp) -> Duration {
64 let delta = self.0.saturating_sub(earlier.0);
65 if delta <= 0 {
66 Duration::ZERO
67 } else {
68 ticks_to_duration(delta)
69 }
70 }
71
72 #[must_use]
74 pub fn is_before(self, other: Timestamp) -> bool {
75 self < other
76 }
77}
78
79#[must_use]
81pub fn duration_to_ticks(duration: Duration) -> i64 {
82 let nanos = duration.as_nanos();
83 let ticks = nanos / (NANOS_PER_TICK as u128);
84 i64::try_from(ticks).unwrap_or(i64::MAX)
85}
86
87#[must_use]
89pub fn ticks_to_duration(ticks: i64) -> Duration {
90 let nanos = (ticks.max(0) as u64).saturating_mul(NANOS_PER_TICK as u64);
91 Duration::from_nanos(nanos)
92}
93
94pub trait Clock: Send + Sync {
99 fn now(&self) -> Timestamp;
101}
102
103impl<T: Clock + ?Sized> Clock for std::sync::Arc<T> {
104 fn now(&self) -> Timestamp {
105 (**self).now()
106 }
107}
108
109#[derive(Debug, Clone, Copy, Default)]
111pub struct SystemClock;
112
113impl Clock for SystemClock {
114 fn now(&self) -> Timestamp {
115 let since_epoch = SystemTime::now()
116 .duration_since(UNIX_EPOCH)
117 .unwrap_or(Duration::ZERO);
118 Timestamp(duration_to_ticks(since_epoch))
119 }
120}
121
122#[derive(Debug)]
127pub struct ManualClock {
128 ticks: AtomicI64,
129}
130
131impl ManualClock {
132 #[must_use]
134 pub fn new(start: Timestamp) -> Self {
135 Self {
136 ticks: AtomicI64::new(start.0),
137 }
138 }
139
140 pub fn advance(&self, duration: Duration) {
142 self.ticks
143 .fetch_add(duration_to_ticks(duration), Ordering::SeqCst);
144 }
145
146 pub fn set(&self, at: Timestamp) {
148 self.ticks.store(at.0, Ordering::SeqCst);
149 }
150}
151
152impl Default for ManualClock {
153 fn default() -> Self {
154 Self::new(Timestamp(1_000_000_000 * TICKS_PER_SECOND))
156 }
157}
158
159impl Clock for ManualClock {
160 fn now(&self) -> Timestamp {
161 Timestamp(self.ticks.load(Ordering::SeqCst))
162 }
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
172pub enum Timeout {
173 #[default]
175 Infinite,
176 After(Duration),
178}
179
180impl Timeout {
181 #[must_use]
183 pub fn from_option(duration: Option<Duration>) -> Self {
184 match duration {
185 Some(d) => Timeout::After(d),
186 None => Timeout::Infinite,
187 }
188 }
189
190 #[must_use]
192 pub fn is_infinite(self) -> bool {
193 matches!(self, Timeout::Infinite)
194 }
195
196 #[must_use]
198 pub fn is_immediate(self) -> bool {
199 matches!(self, Timeout::After(d) if d.is_zero())
200 }
201
202 #[must_use]
204 pub fn as_duration(self) -> Option<Duration> {
205 match self {
206 Timeout::Infinite => None,
207 Timeout::After(d) => Some(d),
208 }
209 }
210
211 #[must_use]
213 pub fn min(self, other: Timeout) -> Timeout {
214 match (self, other) {
215 (Timeout::Infinite, o) => o,
216 (s, Timeout::Infinite) => s,
217 (Timeout::After(a), Timeout::After(b)) => Timeout::After(a.min(b)),
218 }
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225
226 #[test]
227 fn duration_round_trips_through_ticks() {
228 let d = Duration::from_millis(1500);
229 assert_eq!(ticks_to_duration(duration_to_ticks(d)), d);
230 }
231
232 #[test]
233 fn saturating_add_then_since_recovers_duration() {
234 let now = Timestamp::from_ticks(5 * TICKS_PER_SECOND);
235 let later = now.saturating_add(Duration::from_secs(3));
236 assert_eq!(later.saturating_duration_since(now), Duration::from_secs(3));
237 assert_eq!(now.saturating_duration_since(later), Duration::ZERO);
238 }
239
240 #[test]
241 fn manual_clock_advances() {
242 let clock = ManualClock::new(Timestamp::from_ticks(0));
243 assert_eq!(clock.now(), Timestamp::from_ticks(0));
244 clock.advance(Duration::from_secs(2));
245 assert_eq!(clock.now(), Timestamp::from_ticks(2 * TICKS_PER_SECOND));
246 }
247
248 #[test]
249 fn timeout_min_treats_infinite_as_longest() {
250 assert_eq!(
251 Timeout::Infinite.min(Timeout::After(Duration::from_secs(1))),
252 Timeout::After(Duration::from_secs(1))
253 );
254 assert_eq!(
255 Timeout::After(Duration::from_secs(2)).min(Timeout::After(Duration::from_secs(1))),
256 Timeout::After(Duration::from_secs(1))
257 );
258 assert_eq!(Timeout::Infinite.min(Timeout::Infinite), Timeout::Infinite);
259 }
260}