fast_clock/
clock_synchronization.rs1use crate::{CalibratedClock, Clock, DurationCalibration, Time};
2
3pub struct ClockSynchronization<A: Time, B: Time> {
5 epoch_a: A::Instant,
6 epoch_b: B::Instant,
7}
8
9impl<A: Time, B: Time> ClockSynchronization<A, B> {
10 pub fn new(epoch_a: A::Instant, epoch_b: B::Instant) -> Self {
12 ClockSynchronization { epoch_a, epoch_b }
13 }
14
15 pub fn new_aba_calibrated<CA, CB>(a: &CalibratedClock<CA>, b: &CB) -> Self
19 where
20 CA: Clock<Time = A>,
21 CB: Clock<Time = B>,
22 {
23 let (a0, bt, da) = (0..3)
24 .map(|_| {
25 loop {
26 let a0 = a.clock.now();
27 let bt = b.now();
28 let a1 = a.clock.now();
29 if A::instant_cmp(a0, a1).is_le() {
30 let d = A::instant_sub(a1, a0);
31 let da = a.calibration.convert_to_ns(d);
32 break (a0, bt, da);
33 }
34 }
35 })
36 .min_by_key(|(.., da)| *da)
37 .unwrap();
38 ClockSynchronization {
39 epoch_b: bt,
40 epoch_a: A::mixed_add(a0, a.calibration.convert_from_ns(da / 2)),
41 }
42 }
43
44 pub fn to_a<CA, CB>(&self, t: B::Instant, a: &CA, b: &CB) -> A::Instant
48 where
49 CA: DurationCalibration<A::Duration>,
50 CB: DurationCalibration<B::Duration>,
51 {
52 if B::instant_cmp(t, self.epoch_b).is_lt() {
53 let d_b = B::instant_sub(self.epoch_b, t);
54 A::mixed_sub(self.epoch_a, a.convert_from_ns(b.convert_to_ns(d_b)))
55 } else {
56 let d_b = B::instant_sub(t, self.epoch_b);
57 A::mixed_add(self.epoch_a, a.convert_from_ns(b.convert_to_ns(d_b)))
58 }
59 }
60
61 pub fn to_b<CA, CB>(&self, t: A::Instant, a: &CA, b: &CB) -> B::Instant
65 where
66 CA: DurationCalibration<A::Duration>,
67 CB: DurationCalibration<B::Duration>,
68 {
69 if A::instant_cmp(t, self.epoch_a).is_lt() {
70 let d_a = A::instant_sub(self.epoch_a, t);
71 B::mixed_sub(self.epoch_b, b.convert_from_ns(a.convert_to_ns(d_a)))
72 } else {
73 let d_a = A::instant_sub(t, self.epoch_a);
74 B::mixed_add(self.epoch_b, b.convert_from_ns(a.convert_to_ns(d_a)))
75 }
76 }
77
78 pub fn to_a_after_epoch<CA, CB>(&self, t: B::Instant, a: &CA, b: &CB) -> A::Instant
85 where
86 CA: DurationCalibration<A::Duration>,
87 CB: DurationCalibration<B::Duration>,
88 {
89 let d_b = B::instant_sub(t, self.epoch_b);
90 A::mixed_add(self.epoch_a, a.convert_from_ns(b.convert_to_ns(d_b)))
91 }
92
93 pub fn to_b_after_epoch<CA, CB>(&self, t: A::Instant, a: &CA, b: &CB) -> B::Instant
100 where
101 CA: DurationCalibration<A::Duration>,
102 CB: DurationCalibration<B::Duration>,
103 {
104 let d_a = A::instant_sub(t, self.epoch_a);
105 B::mixed_add(self.epoch_b, b.convert_from_ns(a.convert_to_ns(d_a)))
106 }
107
108 pub fn epoch_a(&self) -> A::Instant {
110 self.epoch_a
111 }
112
113 pub fn epoch_b(&self) -> B::Instant {
115 self.epoch_b
116 }
117}
118
119impl<A: Time, B: Time> Clone for ClockSynchronization<A, B> {
120 fn clone(&self) -> Self {
121 *self
122 }
123}
124
125impl<A: Time, B: Time> Copy for ClockSynchronization<A, B> {}
126
127impl<A: Time, B: Time> core::fmt::Debug for ClockSynchronization<A, B>
128where
129 A::Instant: core::fmt::Debug,
130 B::Instant: core::fmt::Debug,
131{
132 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
133 f.debug_struct("ClockSynchronization")
134 .field("epoch_a", &self.epoch_a)
135 .field("epoch_b", &self.epoch_b)
136 .finish()
137 }
138}