1use serde::{Deserialize, Serialize};
6use std::cell::Cell;
7use std::ops::{Add, Rem, Sub};
8#[cfg(all(not(unix), not(windows)))]
9use std::sync::OnceLock;
10#[cfg(all(not(unix), not(windows)))]
11use std::time::Instant;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
17#[cfg_attr(feature = "allocative", derive(allocative::Allocative))]
18pub struct Seconds(pub u32);
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
24#[cfg_attr(feature = "allocative", derive(allocative::Allocative))]
25pub struct Microseconds(pub u64);
26
27impl Seconds {
28 pub fn new(seconds: u32) -> Self {
30 Self(seconds)
31 }
32
33 pub fn now() -> Self {
35 Self(
36 std::time::SystemTime::now()
37 .duration_since(std::time::UNIX_EPOCH)
38 .expect("system time must be after UNIX_EPOCH")
39 .as_secs() as u32,
40 )
41 }
42
43 pub fn get(self) -> u32 {
45 self.0
46 }
47
48 pub fn to_microseconds(self) -> Microseconds {
50 Microseconds(self.0 as u64 * 1_000_000)
51 }
52
53 pub fn saturating_add(self, other: Self) -> Self {
55 Seconds(self.0.saturating_add(other.0))
56 }
57
58 pub fn saturating_sub(self, other: Self) -> Self {
60 Seconds(self.0.saturating_sub(other.0))
61 }
62
63 pub fn checked_add(self, other: Self) -> Option<Self> {
65 self.0.checked_add(other.0).map(Seconds)
66 }
67
68 pub fn checked_sub(self, other: Self) -> Option<Self> {
70 self.0.checked_sub(other.0).map(Seconds)
71 }
72
73 pub fn is_multiple_of(self, other: Self) -> bool {
77 other.0 != 0 && self.0 % other.0 == 0
78 }
79}
80
81impl Microseconds {
82 pub fn new(microseconds: u64) -> Self {
84 Self(microseconds)
85 }
86
87 pub fn now() -> Self {
89 Self(
90 std::time::SystemTime::now()
91 .duration_since(std::time::UNIX_EPOCH)
92 .expect("system time must be after UNIX_EPOCH")
93 .as_micros() as u64,
94 )
95 }
96
97 pub fn get(self) -> u64 {
99 self.0
100 }
101
102 pub fn to_seconds(self) -> Seconds {
104 Seconds((self.0 / 1_000_000) as u32)
105 }
106
107 pub fn saturating_add(self, other: Self) -> Self {
109 Microseconds(self.0.saturating_add(other.0))
110 }
111
112 pub fn saturating_sub(self, other: Self) -> Self {
114 Microseconds(self.0.saturating_sub(other.0))
115 }
116
117 pub fn checked_add(self, other: Self) -> Option<Self> {
119 self.0.checked_add(other.0).map(Microseconds)
120 }
121
122 pub fn checked_sub(self, other: Self) -> Option<Self> {
124 self.0.checked_sub(other.0).map(Microseconds)
125 }
126
127 pub fn is_multiple_of(self, other: Self) -> bool {
131 other.0 != 0 && self.0 % other.0 == 0
132 }
133}
134
135impl From<Seconds> for Microseconds {
136 fn from(s: Seconds) -> Self {
137 s.to_microseconds()
138 }
139}
140
141impl From<u32> for Seconds {
142 fn from(s: u32) -> Self {
143 Seconds(s)
144 }
145}
146
147impl From<u64> for Microseconds {
148 fn from(us: u64) -> Self {
149 Microseconds(us)
150 }
151}
152
153impl Add for Seconds {
155 type Output = Self;
156
157 fn add(self, other: Self) -> Self {
158 Seconds(self.0 + other.0)
159 }
160}
161
162impl Sub for Seconds {
163 type Output = Self;
164
165 fn sub(self, other: Self) -> Self {
166 Seconds(self.0 - other.0)
167 }
168}
169
170impl Rem for Seconds {
171 type Output = Self;
172
173 fn rem(self, other: Self) -> Self {
174 Seconds(self.0 % other.0)
175 }
176}
177
178impl Add for Microseconds {
180 type Output = Self;
181
182 fn add(self, other: Self) -> Self {
183 Microseconds(self.0 + other.0)
184 }
185}
186
187impl Sub for Microseconds {
188 type Output = Self;
189
190 fn sub(self, other: Self) -> Self {
191 Microseconds(self.0 - other.0)
192 }
193}
194
195impl Rem for Microseconds {
196 type Output = Self;
197
198 fn rem(self, other: Self) -> Self {
199 Microseconds(self.0 % other.0)
200 }
201}
202
203impl std::fmt::Display for Seconds {
204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205 write!(f, "{}s", self.0)
206 }
207}
208
209impl std::fmt::Display for Microseconds {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 write!(f, "{}µs", self.0)
212 }
213}
214
215#[derive(Debug)]
222pub struct RealtimeClock {
223 max_seen: Cell<u64>,
224}
225
226impl RealtimeClock {
227 pub fn new() -> Self {
229 Self::with_initial(Microseconds::now())
230 }
231
232 pub fn with_initial(initial: Microseconds) -> Self {
236 Self {
237 max_seen: Cell::new(initial.get()),
238 }
239 }
240
241 pub fn now(&self) -> Microseconds {
245 let current = Microseconds::now();
246 let max = self.max_seen.get();
247
248 let next = if current.get() > max {
249 current.get()
250 } else {
251 max.saturating_add(1)
252 };
253
254 self.max_seen.set(next);
255 Microseconds::new(next)
256 }
257
258 pub fn observe(&self, candidate: Microseconds) -> Microseconds {
263 let max = self.max_seen.get();
264 let next = if candidate.get() > max {
265 candidate.get()
266 } else {
267 max.saturating_add(1)
268 };
269
270 self.max_seen.set(next);
271 Microseconds::new(next)
272 }
273
274 pub fn last_seen(&self) -> Microseconds {
276 Microseconds::new(self.max_seen.get())
277 }
278}
279
280impl Default for RealtimeClock {
281 fn default() -> Self {
282 Self::new()
283 }
284}
285
286pub fn monotonic_now() -> std::io::Result<Microseconds> {
295 #[cfg(unix)]
296 {
297 let mut ts = std::mem::MaybeUninit::<libc::timespec>::uninit();
298 let rc = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, ts.as_mut_ptr()) };
302 if rc != 0 {
303 return Err(std::io::Error::last_os_error());
304 }
305 let ts = unsafe { ts.assume_init() };
309 let seconds = u64::try_from(ts.tv_sec).map_err(|_| {
310 std::io::Error::new(
311 std::io::ErrorKind::InvalidData,
312 "CLOCK_MONOTONIC returned a negative seconds value",
313 )
314 })?;
315 let nanos = u64::try_from(ts.tv_nsec).map_err(|_| {
316 std::io::Error::new(
317 std::io::ErrorKind::InvalidData,
318 "CLOCK_MONOTONIC returned a negative nanoseconds value",
319 )
320 })?;
321 let micros = seconds
322 .checked_mul(1_000_000)
323 .and_then(|value| value.checked_add(nanos / 1_000))
324 .ok_or_else(|| {
325 std::io::Error::new(
326 std::io::ErrorKind::InvalidData,
327 "CLOCK_MONOTONIC microseconds overflowed u64",
328 )
329 })?;
330 Ok(Microseconds::new(micros))
331 }
332
333 #[cfg(windows)]
334 {
335 use windows_sys::Win32::System::WindowsProgramming::QueryUnbiasedInterruptTime;
336
337 let mut ticks_100ns = 0u64;
338 let ok = unsafe { QueryUnbiasedInterruptTime(&mut ticks_100ns) };
342 if ok == 0 {
343 return Err(std::io::Error::last_os_error());
344 }
345 Ok(Microseconds::new(ticks_100ns / 10))
346 }
347
348 #[cfg(all(not(unix), not(windows)))]
349 {
350 static START: OnceLock<Instant> = OnceLock::new();
351 let elapsed = START.get_or_init(Instant::now).elapsed();
352 let micros = u64::try_from(elapsed.as_micros()).map_err(|_| {
353 std::io::Error::new(
354 std::io::ErrorKind::InvalidData,
355 "monotonic elapsed microseconds overflowed u64",
356 )
357 })?;
358 Ok(Microseconds::new(micros))
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365
366 #[test]
367 fn test_seconds_to_microseconds() {
368 let seconds = Seconds::new(42);
369 let micros = seconds.to_microseconds();
370 assert_eq!(micros.get(), 42_000_000);
371 }
372
373 #[test]
374 fn test_microseconds_to_seconds() {
375 let micros = Microseconds::new(42_500_000);
376 let seconds = micros.to_seconds();
377 assert_eq!(seconds.get(), 42);
378 }
379
380 #[test]
381 fn test_conversion_roundtrip() {
382 let original = Seconds::new(100);
383 let roundtrip = original.to_microseconds().to_seconds();
384 assert_eq!(original, roundtrip);
385 }
386
387 #[test]
388 fn test_from_conversions() {
389 let s: Seconds = 42u32.into();
390 assert_eq!(s.get(), 42);
391
392 let us: Microseconds = 42000u64.into();
393 assert_eq!(us.get(), 42000);
394 }
395
396 #[test]
398 fn test_seconds_add() {
399 let a = Seconds::new(10);
400 let b = Seconds::new(20);
401 assert_eq!(a + b, Seconds::new(30));
402 }
403
404 #[test]
405 fn test_seconds_sub() {
406 let a = Seconds::new(30);
407 let b = Seconds::new(10);
408 assert_eq!(a - b, Seconds::new(20));
409 }
410
411 #[test]
412 #[should_panic]
413 fn test_seconds_sub_underflow() {
414 let a = Seconds::new(10);
415 let b = Seconds::new(20);
416 let _ = a - b; }
418
419 #[test]
420 fn test_seconds_rem() {
421 let a = Seconds::new(10);
422 let b = Seconds::new(3);
423 assert_eq!(a % b, Seconds::new(1));
424 }
425
426 #[test]
427 fn test_seconds_saturating_add() {
428 let a = Seconds::new(u32::MAX - 5);
429 let b = Seconds::new(10);
430 assert_eq!(a.saturating_add(b), Seconds::new(u32::MAX));
431 }
432
433 #[test]
434 fn test_seconds_saturating_sub() {
435 let a = Seconds::new(10);
436 let b = Seconds::new(20);
437 assert_eq!(a.saturating_sub(b), Seconds::new(0));
438 }
439
440 #[test]
441 fn test_seconds_checked_add() {
442 let a = Seconds::new(10);
443 let b = Seconds::new(20);
444 assert_eq!(a.checked_add(b), Some(Seconds::new(30)));
445
446 let c = Seconds::new(u32::MAX);
447 let d = Seconds::new(1);
448 assert_eq!(c.checked_add(d), None);
449 }
450
451 #[test]
452 fn test_seconds_checked_sub() {
453 let a = Seconds::new(30);
454 let b = Seconds::new(10);
455 assert_eq!(a.checked_sub(b), Some(Seconds::new(20)));
456
457 let c = Seconds::new(10);
458 let d = Seconds::new(20);
459 assert_eq!(c.checked_sub(d), None);
460 }
461
462 #[test]
463 fn test_seconds_is_multiple_of() {
464 let a = Seconds::new(60);
465 let b = Seconds::new(15);
466 assert!(a.is_multiple_of(b));
467
468 let c = Seconds::new(60);
469 let d = Seconds::new(17);
470 assert!(!c.is_multiple_of(d));
471
472 let e = Seconds::new(0);
473 let f = Seconds::new(10);
474 assert!(e.is_multiple_of(f));
475
476 let g = Seconds::new(10);
477 let h = Seconds::new(0);
478 assert!(!g.is_multiple_of(h)); }
480
481 #[test]
483 fn test_microseconds_add() {
484 let a = Microseconds::new(1000);
485 let b = Microseconds::new(2000);
486 assert_eq!(a + b, Microseconds::new(3000));
487 }
488
489 #[test]
490 fn test_microseconds_sub() {
491 let a = Microseconds::new(3000);
492 let b = Microseconds::new(1000);
493 assert_eq!(a - b, Microseconds::new(2000));
494 }
495
496 #[test]
497 #[should_panic]
498 fn test_microseconds_sub_underflow() {
499 let a = Microseconds::new(1000);
500 let b = Microseconds::new(2000);
501 let _ = a - b; }
503
504 #[test]
505 fn test_microseconds_rem() {
506 let a = Microseconds::new(1000);
507 let b = Microseconds::new(300);
508 assert_eq!(a % b, Microseconds::new(100));
509 }
510
511 #[test]
512 fn test_microseconds_saturating_add() {
513 let a = Microseconds::new(u64::MAX - 5);
514 let b = Microseconds::new(10);
515 assert_eq!(a.saturating_add(b), Microseconds::new(u64::MAX));
516 }
517
518 #[test]
519 fn test_microseconds_saturating_sub() {
520 let a = Microseconds::new(1000);
521 let b = Microseconds::new(2000);
522 assert_eq!(a.saturating_sub(b), Microseconds::new(0));
523 }
524
525 #[test]
526 fn test_microseconds_checked_add() {
527 let a = Microseconds::new(1000);
528 let b = Microseconds::new(2000);
529 assert_eq!(a.checked_add(b), Some(Microseconds::new(3000)));
530
531 let c = Microseconds::new(u64::MAX);
532 let d = Microseconds::new(1);
533 assert_eq!(c.checked_add(d), None);
534 }
535
536 #[test]
537 fn test_microseconds_checked_sub() {
538 let a = Microseconds::new(3000);
539 let b = Microseconds::new(1000);
540 assert_eq!(a.checked_sub(b), Some(Microseconds::new(2000)));
541
542 let c = Microseconds::new(1000);
543 let d = Microseconds::new(2000);
544 assert_eq!(c.checked_sub(d), None);
545 }
546
547 #[test]
548 fn test_microseconds_is_multiple_of() {
549 let a = Microseconds::new(60000);
550 let b = Microseconds::new(15000);
551 assert!(a.is_multiple_of(b));
552
553 let c = Microseconds::new(60000);
554 let d = Microseconds::new(17000);
555 assert!(!c.is_multiple_of(d));
556
557 let e = Microseconds::new(0);
558 let f = Microseconds::new(10000);
559 assert!(e.is_multiple_of(f));
560
561 let g = Microseconds::new(10000);
562 let h = Microseconds::new(0);
563 assert!(!g.is_multiple_of(h)); }
565
566 #[test]
568 fn test_realtime_clock_monotonic() {
569 let clock = RealtimeClock::new();
570 let t1 = clock.now();
571 let t2 = clock.now();
572 let t3 = clock.now();
573
574 assert!(t2 > t1);
575 assert!(t3 > t2);
576 }
577
578 #[test]
579 fn test_realtime_clock_with_initial() {
580 let initial = Microseconds::new(1000000);
581 let clock = RealtimeClock::with_initial(initial);
582
583 assert_eq!(clock.last_seen(), initial);
584
585 let t1 = clock.now();
586 assert!(t1 >= initial);
587 }
588
589 #[test]
590 fn test_realtime_clock_handles_same_time() {
591 let initial = Microseconds::new(1000000);
593 let clock = RealtimeClock::with_initial(initial);
594
595 let t1 = clock.observe(initial);
597 let t2 = clock.observe(initial);
598
599 assert!(t2 > t1);
600 assert_eq!(t2.get() - t1.get(), 1); }
602
603 #[test]
604 fn test_realtime_clock_last_seen() {
605 let clock = RealtimeClock::new();
606
607 let t1 = clock.now();
608 assert_eq!(clock.last_seen(), t1);
609
610 let t2 = clock.now();
611 assert_eq!(clock.last_seen(), t2);
612 }
613
614 #[test]
615 fn test_realtime_clock_forward_jump() {
616 let past = Microseconds::new(1000000);
618 let clock = RealtimeClock::with_initial(past);
619
620 let t1 = clock.now();
622 assert!(t1.get() > past.get());
623 }
624
625 #[test]
626 fn test_realtime_clock_observe_preserves_monotonicity() {
627 let clock = RealtimeClock::with_initial(Microseconds::new(1_000_000));
628
629 let t1 = clock.observe(Microseconds::new(900_000));
630 assert_eq!(t1.get(), 1_000_001);
631
632 let t2 = clock.observe(Microseconds::new(1_000_001));
633 assert_eq!(t2.get(), 1_000_002);
634
635 let t3 = clock.observe(Microseconds::new(1_500_000));
636 assert_eq!(t3.get(), 1_500_000);
637 }
638
639 #[test]
640 fn test_monotonic_now_is_ordered() {
641 let first = monotonic_now().expect("monotonic clock");
642 let second = monotonic_now().expect("monotonic clock");
643 assert!(second >= first);
644 }
645}