spatialrust_sync/
clock.rs1use spatialrust_core::Timestamp;
4
5#[derive(Clone, Debug, PartialEq, Eq, Hash)]
7pub struct ClockId(pub String);
8
9impl ClockId {
10 #[must_use]
12 pub fn new(value: impl Into<String>) -> Self {
13 Self(value.into())
14 }
15
16 #[must_use]
18 pub fn as_str(&self) -> &str {
19 &self.0
20 }
21}
22
23impl From<&str> for ClockId {
24 fn from(value: &str) -> Self {
25 Self(value.to_owned())
26 }
27}
28
29#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
31pub enum ClockDomain {
32 #[default]
34 HostSteady,
35 HostWall,
37 Sensor,
39 External,
41}
42
43#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
45pub struct SyncQuality {
46 pub offset_ns: i64,
48 pub uncertainty_ns: u64,
50 pub estimated: bool,
52}
53
54impl SyncQuality {
55 #[must_use]
57 pub const fn exact() -> Self {
58 Self { offset_ns: 0, uncertainty_ns: 0, estimated: false }
59 }
60
61 #[must_use]
63 pub const fn is_tight(self, max_uncertainty_ns: u64) -> bool {
64 self.uncertainty_ns <= max_uncertainty_ns
65 }
66}
67
68#[derive(Clone, Debug, PartialEq, Eq)]
70pub struct StampedTime {
71 pub clock: ClockId,
73 pub domain: ClockDomain,
75 pub timestamp: Timestamp,
77 pub quality: SyncQuality,
79}
80
81impl StampedTime {
82 #[must_use]
84 pub fn exact(clock: impl Into<ClockId>, domain: ClockDomain, timestamp: Timestamp) -> Self {
85 Self { clock: clock.into(), domain, timestamp, quality: SyncQuality::exact() }
86 }
87
88 #[must_use]
90 pub const fn as_nanos(&self) -> u64 {
91 self.timestamp.as_nanos()
92 }
93
94 #[must_use]
96 pub fn abs_delta_ns(&self, other: &Self) -> u64 {
97 let a = self.as_nanos();
98 let b = other.as_nanos();
99 a.abs_diff(b)
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::{ClockDomain, StampedTime, SyncQuality};
106 use spatialrust_core::Timestamp;
107
108 #[test]
109 fn tight_sync_rejects_high_uncertainty() {
110 let quality = SyncQuality { offset_ns: 0, uncertainty_ns: 5_000_000, estimated: true };
111 assert!(!quality.is_tight(1_000_000));
112 let stamp = StampedTime::exact("host", ClockDomain::HostSteady, Timestamp::from_nanos(10));
113 assert_eq!(stamp.as_nanos(), 10);
114 }
115}