1use std::time::Instant;
9
10pub fn monotonic_now_ns() -> i64 {
15 monotonic_base().elapsed().as_nanos() as i64
16}
17
18fn monotonic_base() -> Instant {
20 use std::sync::OnceLock;
21 static BASE: OnceLock<Instant> = OnceLock::new();
22 *BASE.get_or_init(Instant::now)
23}
24
25#[derive(Debug, Clone)]
34pub struct ClockNormalizer {
35 device_origin_ns: Option<i64>,
37 monotonic_origin_ns: i64,
39}
40
41impl ClockNormalizer {
42 pub fn new() -> Self {
44 Self {
45 device_origin_ns: None,
46 monotonic_origin_ns: 0,
47 }
48 }
49
50 pub fn is_unset(&self) -> bool {
52 self.device_origin_ns.is_none()
53 }
54
55 pub fn normalize(&mut self, device_pts_ns: i64) -> i64 {
60 match self.device_origin_ns {
61 Some(origin) => self.monotonic_origin_ns + device_pts_ns.wrapping_sub(origin),
62 None => {
63 self.device_origin_ns = Some(device_pts_ns);
64 self.monotonic_origin_ns = monotonic_now_ns();
65 self.monotonic_origin_ns
66 }
67 }
68 }
69}
70
71impl Default for ClockNormalizer {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn monotonic_is_non_decreasing() {
83 let a = monotonic_now_ns();
84 let b = monotonic_now_ns();
85 assert!(b >= a);
86 }
87
88 #[test]
89 fn first_sample_sets_origin_and_preserves_deltas() {
90 let mut n = ClockNormalizer::new();
91 assert!(n.is_unset());
92 let t0 = n.normalize(1_000_000); assert!(!n.is_unset());
95 let t1 = n.normalize(6_000_000);
97 assert_eq!(t1 - t0, 5_000_000);
98 let t2 = n.normalize(4_000_000);
100 assert_eq!(t2 - t0, 3_000_000);
101 }
102
103 #[test]
108 fn normalize_wrapping_sub_handles_i64_boundary() {
109 let mut n = ClockNormalizer::new();
110 let base = n.normalize(i64::MAX);
112 let next = n.normalize(i64::MIN);
115 assert_eq!(
116 next.wrapping_sub(base),
117 1,
118 "wrapping_sub 境界: MIN - MAX はラップして +1 のはず"
119 );
120 }
121
122 #[test]
125 fn first_normalize_ignores_device_value_for_origin() {
126 let mut n = ClockNormalizer::new();
127 let before = monotonic_now_ns();
129 let t0 = n.normalize(i64::MIN);
130 let after = monotonic_now_ns();
131 assert!(
132 t0 >= before && t0 <= after,
133 "初回は monotonic 原点を返すはず: {before} <= {t0} <= {after}"
134 );
135 assert!(!n.is_unset());
136 }
137
138 #[test]
140 fn default_is_unset_like_new() {
141 let n = ClockNormalizer::default();
142 assert!(n.is_unset());
143 }
144}