1#[cfg(test)]
2#[macro_use]
3extern crate approx;
4use bincode::de::BorrowDecoder;
5use bincode::de::Decoder;
6use bincode::enc::Encoder;
7use bincode::error::{DecodeError, EncodeError};
8use bincode::BorrowDecode;
9use bincode::{Decode, Encode};
10use core::ops::{Add, Sub};
11pub use quanta::Instant;
12use quanta::{Clock, Mock};
13use serde::{Deserialize, Serialize};
14use std::convert::Into;
15use std::fmt::{Display, Formatter};
16use std::ops::{AddAssign, Div, Mul, SubAssign};
17use std::sync::Arc;
18use std::time::Duration;
19
20#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)]
23pub struct CuDuration(pub u64);
24
25impl CuDuration {
26 pub const MIN: CuDuration = CuDuration(0u64);
28 pub const MAX: CuDuration = CuDuration(NONE_VALUE - 1);
30 pub fn max(self, other: CuDuration) -> CuDuration {
31 let Self(lhs) = self;
32 let Self(rhs) = other;
33 CuDuration(lhs.max(rhs))
34 }
35
36 pub fn min(self, other: CuDuration) -> CuDuration {
37 let Self(lhs) = self;
38 let Self(rhs) = other;
39 CuDuration(lhs.min(rhs))
40 }
41
42 pub fn as_nanos(&self) -> u64 {
43 let Self(nanos) = self;
44 *nanos
45 }
46}
47
48impl From<Duration> for CuDuration {
50 fn from(duration: Duration) -> Self {
51 CuDuration(duration.as_nanos() as u64)
52 }
53}
54
55impl From<CuDuration> for Duration {
56 fn from(val: CuDuration) -> Self {
57 let CuDuration(nanos) = val;
58 Duration::from_nanos(nanos)
59 }
60}
61
62impl From<u64> for CuDuration {
63 fn from(duration: u64) -> Self {
64 CuDuration(duration)
65 }
66}
67
68impl From<CuDuration> for u64 {
69 fn from(val: CuDuration) -> Self {
70 let CuDuration(nanos) = val;
71 nanos
72 }
73}
74
75impl Sub for CuDuration {
76 type Output = Self;
77
78 fn sub(self, rhs: Self) -> Self::Output {
79 let CuDuration(lhs) = self;
80 let CuDuration(rhs) = rhs;
81 CuDuration(lhs - rhs)
82 }
83}
84
85impl Add for CuDuration {
86 type Output = Self;
87
88 fn add(self, rhs: Self) -> Self::Output {
89 let CuDuration(lhs) = self;
90 let CuDuration(rhs) = rhs;
91 CuDuration(lhs + rhs)
92 }
93}
94
95impl AddAssign for CuDuration {
96 fn add_assign(&mut self, rhs: Self) {
97 let CuDuration(lhs) = self;
98 let CuDuration(rhs) = rhs;
99 *lhs += rhs;
100 }
101}
102
103impl SubAssign for CuDuration {
104 fn sub_assign(&mut self, rhs: Self) {
105 let CuDuration(lhs) = self;
106 let CuDuration(rhs) = rhs;
107 *lhs -= rhs;
108 }
109}
110
111impl<T> Div<T> for CuDuration
114where
115 T: Into<u64>,
116{
117 type Output = Self;
118 fn div(self, rhs: T) -> Self {
119 let CuDuration(lhs) = self;
120 CuDuration(lhs / rhs.into())
121 }
122}
123impl<T> Mul<T> for CuDuration
128where
129 T: Into<u64>,
130{
131 type Output = CuDuration;
132
133 fn mul(self, rhs: T) -> CuDuration {
134 let CuDuration(lhs) = self;
135 CuDuration(lhs * rhs.into())
136 }
137}
138
139impl Mul<CuDuration> for u64 {
141 type Output = CuDuration;
142
143 fn mul(self, rhs: CuDuration) -> CuDuration {
144 let CuDuration(nanos) = rhs;
145 CuDuration(self * nanos)
146 }
147}
148
149impl Mul<CuDuration> for u32 {
151 type Output = CuDuration;
152
153 fn mul(self, rhs: CuDuration) -> CuDuration {
154 let CuDuration(nanos) = rhs;
155 CuDuration(self as u64 * nanos)
156 }
157}
158
159impl Mul<CuDuration> for i32 {
161 type Output = CuDuration;
162
163 fn mul(self, rhs: CuDuration) -> CuDuration {
164 let CuDuration(nanos) = rhs;
165 CuDuration(self as u64 * nanos)
166 }
167}
168
169impl Encode for CuDuration {
170 fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
171 let CuDuration(nanos) = self;
172 nanos.encode(encoder)
173 }
174}
175
176impl<Context> Decode<Context> for CuDuration {
177 fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
178 Ok(CuDuration(u64::decode(decoder)?))
179 }
180}
181
182impl<'de, Context> BorrowDecode<'de, Context> for CuDuration {
183 fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
184 Ok(CuDuration(u64::decode(decoder)?))
185 }
186}
187
188impl Display for CuDuration {
189 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
190 let Self(nanos) = *self;
191 if nanos >= 86_400_000_000_000 {
192 write!(f, "{:.3} d", nanos as f64 / 86_400_000_000_000.0)
193 } else if nanos >= 3_600_000_000_000 {
194 write!(f, "{:.3} h", nanos as f64 / 3_600_000_000_000.0)
195 } else if nanos >= 60_000_000_000 {
196 write!(f, "{:.3} m", nanos as f64 / 60_000_000_000.0)
197 } else if nanos >= 1_000_000_000 {
198 write!(f, "{:.3} s", nanos as f64 / 1_000_000_000.0)
199 } else if nanos >= 1_000_000 {
200 write!(f, "{:.3} ms", nanos as f64 / 1_000_000.0)
201 } else if nanos >= 1_000 {
202 write!(f, "{:.3} µs", nanos as f64 / 1_000.0)
203 } else {
204 write!(f, "{nanos} ns")
205 }
206 }
207}
208
209pub type CuTime = CuDuration;
211
212#[derive(Copy, Clone, Debug, PartialEq, Encode, Decode, Serialize, Deserialize)]
214pub struct OptionCuTime(CuTime);
215
216const NONE_VALUE: u64 = 0xFFFFFFFFFFFFFFFF;
217
218impl OptionCuTime {
219 #[inline]
220 pub fn is_none(&self) -> bool {
221 let Self(CuDuration(nanos)) = self;
222 *nanos == NONE_VALUE
223 }
224
225 #[inline]
226 pub fn none() -> Self {
227 OptionCuTime(CuDuration(NONE_VALUE))
228 }
229
230 #[inline]
231 pub fn unwrap(self) -> CuTime {
232 if self.is_none() {
233 panic!("called `OptionCuTime::unwrap()` on a `None` value");
234 }
235 self.0
236 }
237}
238
239impl Display for OptionCuTime {
240 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
241 if self.is_none() {
242 write!(f, "None")
243 } else {
244 write!(f, "{}", self.0)
245 }
246 }
247}
248
249impl Default for OptionCuTime {
250 fn default() -> Self {
251 Self::none()
252 }
253}
254
255impl From<Option<CuTime>> for OptionCuTime {
256 #[inline]
257 fn from(duration: Option<CuTime>) -> Self {
258 match duration {
259 Some(duration) => OptionCuTime(duration),
260 None => OptionCuTime(CuDuration(NONE_VALUE)),
261 }
262 }
263}
264
265impl From<OptionCuTime> for Option<CuTime> {
266 #[inline]
267 fn from(val: OptionCuTime) -> Self {
268 let OptionCuTime(CuDuration(nanos)) = val;
269 if nanos == NONE_VALUE {
270 None
271 } else {
272 Some(CuDuration(nanos))
273 }
274 }
275}
276
277impl From<CuTime> for OptionCuTime {
278 #[inline]
279 fn from(val: CuTime) -> Self {
280 Some(val).into()
281 }
282}
283
284#[derive(Copy, Clone, Debug, Encode, Decode, Serialize, Deserialize, PartialEq)]
286pub struct CuTimeRange {
287 pub start: CuTime,
288 pub end: CuTime,
289}
290
291impl From<&[CuTime]> for CuTimeRange {
294 fn from(slice: &[CuTime]) -> Self {
295 CuTimeRange {
296 start: *slice.iter().min().expect("Empty slice"),
297 end: *slice.iter().max().expect("Empty slice"),
298 }
299 }
300}
301
302#[derive(Copy, Clone, Debug, Encode, Decode, Serialize, Deserialize)]
304pub struct PartialCuTimeRange {
305 pub start: OptionCuTime,
306 pub end: OptionCuTime,
307}
308
309impl Default for PartialCuTimeRange {
310 fn default() -> Self {
311 PartialCuTimeRange {
312 start: OptionCuTime::none(),
313 end: OptionCuTime::none(),
314 }
315 }
316}
317
318#[derive(Default, Clone, Debug, PartialEq, Encode, Decode, Serialize, Deserialize, Copy)]
321pub enum Tov {
322 #[default]
323 None,
324 Time(CuTime),
325 Range(CuTimeRange),
326}
327
328impl From<Option<CuDuration>> for Tov {
329 fn from(duration: Option<CuDuration>) -> Self {
330 match duration {
331 Some(duration) => Tov::Time(duration),
332 None => Tov::None,
333 }
334 }
335}
336
337impl From<CuDuration> for Tov {
338 fn from(duration: CuDuration) -> Self {
339 Tov::Time(duration)
340 }
341}
342
343#[derive(Clone, Debug)]
347pub struct RobotClock {
348 inner: Clock, ref_time: Instant, }
351
352#[derive(Debug, Clone)]
354pub struct RobotClockMock(Arc<Mock>); impl RobotClockMock {
357 pub fn increment(&self, amount: Duration) {
358 let Self(mock) = self;
359 mock.increment(amount);
360 }
361
362 pub fn decrement(&self, amount: Duration) {
365 let Self(mock) = self;
366 mock.decrement(amount);
367 }
368
369 pub fn value(&self) -> u64 {
371 let Self(mock) = self;
372 mock.value()
373 }
374
375 pub fn now(&self) -> CuTime {
377 let Self(mock) = self;
378 mock.value().into()
379 }
380
381 pub fn set_value(&self, value: u64) {
383 let Self(mock) = self;
384 let v = mock.value();
385 if v < value {
387 self.increment(Duration::from_nanos(value) - Duration::from_nanos(v));
388 } else {
389 self.decrement(Duration::from_nanos(v) - Duration::from_nanos(value));
390 }
391 }
392}
393
394impl RobotClock {
395 pub fn new() -> Self {
398 let clock = Clock::new();
399 let ref_time = clock.now();
400 RobotClock {
401 inner: clock,
402 ref_time,
403 }
404 }
405
406 pub fn from_ref_time(ref_time_ns: u64) -> Self {
408 let clock = Clock::new();
409 let ref_time = clock.now() - Duration::from_nanos(ref_time_ns);
410 RobotClock {
411 inner: Clock::new(),
412 ref_time,
413 }
414 }
415
416 pub fn mock() -> (Self, RobotClockMock) {
419 let (clock, mock) = Clock::mock();
420 let ref_time = clock.now();
421 (
422 RobotClock {
423 inner: clock,
424 ref_time,
425 },
426 RobotClockMock(mock),
427 )
428 }
429
430 #[inline]
433 pub fn now(&self) -> CuTime {
434 (self.inner.now() - self.ref_time).into()
437 }
438
439 #[inline]
441 pub fn recent(&self) -> CuTime {
442 (self.inner.recent() - self.ref_time).into()
443 }
444}
445
446impl Default for RobotClock {
447 fn default() -> Self {
448 Self::new()
449 }
450}
451
452pub trait ClockProvider {
454 fn get_clock(&self) -> RobotClock;
455}
456
457#[cfg(test)]
458mod tests {
459 use super::*;
460
461 #[test]
462 fn test_mock() {
463 let (clock, mock) = RobotClock::mock();
464 assert_eq!(clock.now(), Duration::from_secs(0).into());
465 mock.increment(Duration::from_secs(1));
466 assert_eq!(clock.now(), Duration::from_secs(1).into());
467 }
468
469 #[test]
470 fn test_mock_clone() {
471 let (clock, mock) = RobotClock::mock();
472 assert_eq!(clock.now(), Duration::from_secs(0).into());
473 let clock_clone = clock.clone();
474 mock.increment(Duration::from_secs(1));
475 assert_eq!(clock_clone.now(), Duration::from_secs(1).into());
476 }
477
478 #[test]
479 fn test_from_ref_time() {
480 let tolerance_ms = 10;
481 let clock = RobotClock::from_ref_time(1_000_000_000);
482 assert_relative_eq!(
483 <CuDuration as Into<Duration>>::into(clock.now()).as_millis() as f64,
484 Duration::from_secs(1).as_millis() as f64,
485 epsilon = tolerance_ms as f64
486 );
487 }
488
489 #[test]
490 fn longest_duration() {
491 let maxcu = CuDuration(u64::MAX);
492 let maxd: Duration = maxcu.into();
493 assert_eq!(maxd.as_nanos(), u64::MAX as u128);
494 let s = maxd.as_secs();
495 let y = s / 60 / 60 / 24 / 365;
496 assert!(y >= 584); }
498
499 #[test]
500 fn test_some_time_arithmetics() {
501 let a: CuDuration = 10.into();
502 let b: CuDuration = 20.into();
503 let c = a + b;
504 assert_eq!(c.0, 30);
505 let d = b - a;
506 assert_eq!(d.0, 10);
507 }
508
509 #[test]
510 fn test_build_range_from_slice() {
511 let range = CuTimeRange::from(&[20.into(), 10.into(), 30.into()][..]);
512 assert_eq!(range.start, 10.into());
513 assert_eq!(range.end, 30.into());
514 }
515}