1use crate::epoch::Epoch;
2use ::std::time::Duration;
3
4pub trait MonotonicClock {
31 fn epoch(&self) -> Epoch;
33
34 fn now(&self) -> Duration;
36
37 fn is_ticking(&self) -> bool;
39
40 #[inline]
42 fn time(&self) -> Duration {
43 self.now() + *self.epoch()
44 }
45
46 #[inline]
48 fn time_as_float(&self) -> f64 {
49 let time = self.time();
50 time.as_secs() as f64 + time.subsec_nanos() as f64 * 1e-9
51 }
52
53 #[inline]
57 fn as_float(&self) -> f64 {
58 self.time_as_float()
59 }
60}
61
62#[derive(Debug, Clone)]
65pub struct Clock {
66 inner: ::std::sync::Arc<::std::sync::RwLock<InnerClock>>,
67}
68
69unsafe impl Sync for Clock {}
70unsafe impl Send for Clock {}
71
72impl Clock {
73 pub fn new() -> Self {
75 Self {
76 inner: ::std::sync::Arc::new(::std::sync::RwLock::new(InnerClock::new())),
77 }
78 }
79
80 pub fn now(&self) -> Duration {
82 self.inner.read().unwrap().now()
83 }
84
85 pub fn start(&self) {
87 self.inner.write().unwrap().start();
88 }
89
90 pub fn stop(&self) -> Option<Duration> {
92 self.inner.write().unwrap().stop()
93 }
94
95 pub fn reset(&self) {
97 self.inner.write().unwrap().reset();
98 }
99
100 pub fn resume(&self) -> Option<Duration> {
102 self.inner.write().unwrap().resume()
103 }
104}
105
106impl MonotonicClock for Clock {
107 fn epoch(&self) -> Epoch {
108 self.inner.read().unwrap().epoch()
109 }
110
111 fn now(&self) -> Duration {
112 self.inner.read().unwrap().now()
113 }
114
115 fn is_ticking(&self) -> bool {
116 self.inner.read().unwrap().is_ticking()
117 }
118}
119
120impl Default for Clock {
121 #[inline]
122 fn default() -> Self {
123 Self::new()
124 }
125}
126
127#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
128struct InnerClock {
129 epoch: Epoch, start: ::std::time::Instant,
131 stop: Option<::std::time::Instant>,
132}
133
134impl InnerClock {
135 #[inline]
137 pub fn new() -> Self {
138 Self {
139 epoch: Epoch::from_unix(),
140 start: ::std::time::Instant::now(),
141 stop: None,
142 }
143 }
144
145 #[inline]
147 pub fn epoch(&self) -> Epoch {
148 self.epoch
149 }
150
151 #[inline]
153 pub fn reset(&mut self) {
154 self.epoch = Epoch::from_unix();
155 self.start = ::std::time::Instant::now();
156 self.stop = None;
157 }
158
159 #[inline]
161 pub fn start(&mut self) {
162 self.start = ::std::time::Instant::now();
163 self.stop = None;
164 }
165
166 #[inline]
170 pub fn resume(&mut self) -> Option<Duration> {
171 if let Some(stop) = self.stop {
172 self.stop = None;
173 ::std::time::Instant::now().checked_duration_since(stop)
174 } else {
175 Some(Duration::new(0, 0))
176 }
177 }
178
179 #[inline]
182 pub fn stop(&mut self) -> Option<Duration> {
183 if self.stop.is_none() {
184 self.stop = Some(::std::time::Instant::now());
185 }
186 self.stop.map(|stop| stop - self.start)
187 }
188
189 #[inline]
191 pub fn now(&self) -> Duration {
192 if let Some(stop) = self.stop {
193 stop.duration_since(self.start)
194 } else {
195 ::std::time::Instant::now().duration_since(self.start)
196 }
197 }
198
199 #[inline]
201 pub fn is_ticking(&self) -> bool {
202 self.stop.is_none()
203 }
204}
205
206impl Default for InnerClock {
207 #[inline]
208 fn default() -> Self {
209 Self::new()
210 }
211}
212
213impl MonotonicClock for InnerClock {
214 #[inline]
215 fn epoch(&self) -> Epoch {
216 self.epoch
217 }
218
219 #[inline]
220 fn now(&self) -> Duration {
221 self.now()
222 }
223
224 #[inline]
225 fn is_ticking(&self) -> bool {
226 self.is_ticking()
227 }
228}
229
230impl ::std::fmt::Display for InnerClock {
231 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
232 write!(f, "{}", self.time_as_float())
233 }
234}
235
236impl ::std::convert::From<InnerClock> for Duration {
237 fn from(mc: InnerClock) -> Self {
239 mc.time()
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246 use assert2::assert;
247 #[test]
248 fn test_monotonic_clock() {
249 let clock = Clock::new();
250 assert!(clock.now() < Duration::from_secs(1));
251 ::std::thread::sleep(Duration::from_secs(1));
252 assert!(clock.now() > Duration::from_secs(1));
253 ::std::thread::sleep(Duration::from_secs(2));
254
255 let stopped_at = clock.stop().unwrap();
256 assert!(clock.now() > Duration::from_secs(2));
257 assert!(clock.now() == stopped_at);
258
259 ::std::thread::sleep(Duration::from_secs(2));
260 assert!(clock.now() > Duration::from_secs(2));
261 assert!(clock.now() == stopped_at);
262
263 clock.resume();
264 ::std::thread::sleep(Duration::from_secs(1));
265 assert!(clock.now() > stopped_at);
266 clock.reset();
267 assert!(clock.now() < Duration::from_secs(1));
268 }
269
270 #[test]
271 fn test_monotonic_clock_since_unix_epoch() {
272 let clock = Clock::new();
273 eprintln!("clock.epoch = {:?}", clock.epoch());
274 eprintln!("clock.now() = {:?}", clock.time());
275 }
276}