fast_clock/
wrapping_u64.rs1#[cfg(feature = "std")]
2use crate::std_clocks::InstantTime;
3use crate::{CalibratedClock, Clock, ClockSynchronization, DurationCalibration, Time};
4use core::cmp::{self};
5
6#[derive(Copy, Clone, Debug)]
11pub struct WrappingU64Time;
12
13#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
15pub struct WrappingU64Instant(pub u64);
16
17#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
19pub struct WrappingU64Duration(pub u64);
20
21impl Time for WrappingU64Time {
22 type Instant = WrappingU64Instant;
23
24 type Duration = WrappingU64Duration;
25
26 #[inline]
27 fn instant_sub(a: Self::Instant, b: Self::Instant) -> Self::Duration {
28 debug_assert!(Self::instant_cmp(a, b).is_ge());
29 WrappingU64Duration(a.0.wrapping_sub(b.0))
30 }
31
32 #[inline]
33 fn duration_sub(a: Self::Duration, b: Self::Duration) -> Self::Duration {
34 WrappingU64Duration(a.0 - b.0)
35 }
36
37 #[inline]
38 fn duration_add(a: Self::Duration, b: Self::Duration) -> Self::Duration {
39 WrappingU64Duration(a.0 + b.0)
40 }
41
42 #[inline]
43 fn mixed_sub(a: Self::Instant, b: Self::Duration) -> Self::Instant {
44 WrappingU64Instant(a.0.wrapping_sub(b.0))
45 }
46
47 #[inline]
48 fn mixed_add(a: Self::Instant, b: Self::Duration) -> Self::Instant {
49 WrappingU64Instant(a.0.wrapping_add(b.0))
50 }
51
52 #[inline]
53 fn instant_cmp(a: Self::Instant, b: Self::Instant) -> cmp::Ordering {
54 (a.0 as i64).wrapping_sub(b.0 as i64).cmp(&0)
55 }
56}
57
58#[derive(Clone, Copy, Debug)]
62pub struct U64Calibration {
63 to_ns: u64,
64 to_ns_shift: u32,
65 from_ns: u64,
66 from_ns_shift: u32,
67}
68
69impl U64Calibration {
70 pub fn new(duration: WrappingU64Duration, duration_ns: u64) -> Self {
72 assert!(duration.0 > 0);
73 assert!(duration_ns > 0);
74 let (to_ns, to_ns_shift) = make_mul_shift(duration.0, duration_ns);
75 let (from_ns, from_ns_shift) = make_mul_shift(duration_ns, duration.0);
76 U64Calibration {
77 to_ns,
78 to_ns_shift,
79 from_ns,
80 from_ns_shift,
81 }
82 }
83
84 pub fn new_with_reference_clock<C: Clock<Time = WrappingU64Time>, R: Clock>(
89 clock: &C,
90 reference_clock: &CalibratedClock<R>,
91 min_duration: <R::Time as Time>::Duration,
92 mut wait: impl FnMut(<R::Time as Time>::Instant),
93 ) -> (Self, ClockSynchronization<R::Time, C::Time>) {
94 let s1 = ClockSynchronization::new_aba_calibrated(reference_clock, clock);
95 let wait_until = R::Time::mixed_add(s1.epoch_a(), min_duration);
96 while R::Time::instant_cmp(reference_clock.clock.now(), wait_until).is_lt() {
97 wait(wait_until);
98 }
99 let s2 = ClockSynchronization::new_aba_calibrated(reference_clock, clock);
100 (
101 Self::new(
102 C::Time::instant_sub(s2.epoch_b(), s1.epoch_b()),
103 reference_clock
104 .calibration
105 .convert_to_ns(R::Time::instant_sub(s2.epoch_a(), s1.epoch_a())),
106 ),
107 s2,
108 )
109 }
110
111 #[cfg(feature = "std")]
115 pub fn new_with_std_instant<C: Clock<Time = WrappingU64Time>>(
116 clock: &C,
117 min_duration: std::time::Duration,
118 ) -> (Self, ClockSynchronization<InstantTime, C::Time>) {
119 use crate::{InherentlyCalibrated, std_clocks::InstantClock};
120
121 Self::new_with_reference_clock(
122 clock,
123 &CalibratedClock {
124 clock: InstantClock,
125 calibration: InherentlyCalibrated,
126 },
127 min_duration,
128 |until| {
129 let now = std::time::Instant::now();
130 if let Some(remaining) = until.checked_duration_since(now) {
131 std::thread::sleep(remaining);
132 }
133 },
134 )
135 }
136}
137
138impl DurationCalibration<WrappingU64Duration> for U64Calibration {
139 #[inline]
140 fn convert_to_ns(&self, d: WrappingU64Duration) -> u64 {
141 apply_mul_shift(d.0, self.to_ns, self.to_ns_shift)
142 }
143
144 #[inline]
145 fn convert_from_ns(&self, ns: u64) -> WrappingU64Duration {
146 WrappingU64Duration(apply_mul_shift(ns, self.from_ns, self.from_ns_shift))
147 }
148}
149
150fn make_mul_shift(from: u64, to: u64) -> (u64, u32) {
151 debug_assert!(from > 0 && from < (1 << 63));
152 debug_assert!(to > 0 && to < (1 << 63));
153
154 let l_to = 64 - to.leading_zeros();
155 let l_from = 64 - from.leading_zeros();
156 let s0 = l_from + 64 - l_to;
157
158 let shift = if (to as u128) << s0 < (from as u128) << 64 {
159 s0
160 } else {
161 s0 - 1
162 };
163
164 let mul = (((to as u128) << shift) / from as u128) as u64;
165 (mul, shift)
166}
167
168#[inline]
169fn apply_mul_shift(x: u64, mul: u64, shift: u32) -> u64 {
170 ((mul as u128 * x as u128 + (1u128 << (shift - 1))) >> shift) as u64
171}
172
173#[test]
174fn test_make_mul_shift() {
175 use std::vec::Vec;
176 let mut values: Vec<u64> = (1..61)
177 .flat_map(|s| (1..4).map(move |i| i << s))
178 .flat_map(|x| [x - 1, x, x + 1])
179 .filter(|&x| x > 0 && x < (1 << 63))
180 .collect();
181 values.sort_unstable();
182 values.dedup();
183 for &from in &values {
184 for &to in &values {
185 let (mul, shift) = make_mul_shift(from, to);
186 assert!(mul >= (1 << 63));
187 assert_eq!(apply_mul_shift(from, mul, shift), to);
188 }
189 }
190}