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