Skip to main content

statime_base/
identifiers.rs

1use core::sync::atomic::AtomicUsize;
2
3/// Unique identifier for a clock
4#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
5pub struct ClockId(usize);
6
7impl ClockId {
8    /// Get a new identifier for a clock.
9    #[expect(
10        clippy::new_without_default,
11        reason = "The new value is non-trivial and non-constant, therefore not fitting for default."
12    )]
13    pub fn new() -> ClockId {
14        static COUNTER: AtomicUsize = AtomicUsize::new(0);
15        ClockId(COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed))
16    }
17}
18
19/// Unique identifier for a link
20///
21/// This consists of the two clocks that are linked, and a unique identifier for the link itself.
22/// A link has no direction in nature, so the order of the clocks does not matter. The third
23/// element, the unique identifier, is used to distinguish between multiple links between the same
24/// two clocks.
25#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
26pub struct LinkId(ClockId, ClockId, usize);
27
28impl LinkId {
29    /// Get a new identifier for a clock.
30    pub fn new(a: ClockId, b: ClockId) -> Option<LinkId> {
31        static COUNTER: AtomicUsize = AtomicUsize::new(0);
32
33        if a == b {
34            None
35        } else {
36            Some(LinkId(
37                a,
38                b,
39                COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed),
40            ))
41        }
42    }
43
44    /// Get the first clock in the link.
45    #[must_use]
46    pub fn first_clock(self) -> ClockId {
47        self.0
48    }
49
50    /// Get the second clock in the link.
51    #[must_use]
52    pub fn second_clock(self) -> ClockId {
53        self.1
54    }
55
56    /// Check if the given clock is part of a link.
57    #[must_use]
58    pub fn contains_clock(self, clock: ClockId) -> bool {
59        self.0 == clock || self.1 == clock
60    }
61
62    /// Get a directed link identifier for the link in the forward direction.
63    ///
64    /// This is the direction from the first to the second clock.
65    #[must_use]
66    pub fn forward(self) -> DirectedLinkId {
67        DirectedLinkId(self, Direction::Forward)
68    }
69
70    /// Get a directed link identifier for the link in the reverse direction.
71    ///
72    /// This is the direction from the second to the first clock.
73    #[must_use]
74    pub fn reverse(self) -> DirectedLinkId {
75        DirectedLinkId(self, Direction::Reverse)
76    }
77}
78
79/// An identifier for a link with a specific direction.
80#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
81pub struct DirectedLinkId(LinkId, Direction);
82
83impl DirectedLinkId {
84    /// Create a new directed link identifier.
85    #[must_use]
86    pub fn new(link_id: LinkId, direction: Direction) -> DirectedLinkId {
87        DirectedLinkId(link_id, direction)
88    }
89
90    /// Retrieve the link identifier for the directed link.
91    #[must_use]
92    pub fn link_id(self) -> LinkId {
93        self.0
94    }
95
96    /// Return the direction of the directed link.
97    #[must_use]
98    pub fn direction(self) -> Direction {
99        self.1
100    }
101
102    /// Reverse the directed link to the other way.
103    #[must_use]
104    pub fn reverse(self) -> DirectedLinkId {
105        DirectedLinkId::new(self.0, self.1.reverse())
106    }
107
108    /// Return the clock that is the source of the directed link.
109    #[must_use]
110    pub fn from_clock(self) -> ClockId {
111        match self.1 {
112            Direction::Forward => self.0.first_clock(),
113            Direction::Reverse => self.0.second_clock(),
114        }
115    }
116
117    /// Return the clock that is the destination of the directed link.
118    #[must_use]
119    pub fn to_clock(self) -> ClockId {
120        match self.1 {
121            Direction::Forward => self.0.second_clock(),
122            Direction::Reverse => self.0.first_clock(),
123        }
124    }
125
126    /// Returns true if the two directed links are the same link but in opposite directions.
127    #[must_use]
128    pub fn is_reverse_of(self, other: DirectedLinkId) -> bool {
129        self.0 == other.0 && self.1.is_reverse_of(other.1)
130    }
131}
132
133/// Direction of a directed link. This is used to indicate which direction a
134/// measurement is being made in.
135#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
136pub enum Direction {
137    /// The direction from the first clock to the second clock.
138    Forward,
139    /// The direction from the second clock to the first clock.
140    Reverse,
141}
142
143impl Direction {
144    /// Reverse the direction.
145    #[must_use]
146    pub fn reverse(self) -> Direction {
147        match self {
148            Direction::Forward => Direction::Reverse,
149            Direction::Reverse => Direction::Forward,
150        }
151    }
152
153    /// Returns true if the two directed links are the same link but in opposite directions.
154    #[must_use]
155    pub fn is_reverse_of(self, other: Direction) -> bool {
156        self != other
157    }
158}
159
160/// The type of a used source of time.
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
162#[non_exhaustive]
163pub enum SourceType {
164    /// A generic pulse-per-second source
165    Pps,
166    /// A socket source
167    Sock,
168    /// An NTP source.
169    Ntp,
170    /// A CSPTP source.
171    Csptp,
172}