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(Default, Copy, Clone, Debug, Encode, Decode, Serialize, Deserialize)]
304pub struct PartialCuTimeRange {
305 pub start: OptionCuTime,
306 pub end: OptionCuTime,
307}
308
309#[derive(Default, Clone, Debug, PartialEq, Encode, Decode, Serialize, Deserialize, Copy)]
312pub enum Tov {
313 #[default]
314 None,
315 Time(CuTime),
316 Range(CuTimeRange),
317}
318
319impl From<Option<CuDuration>> for Tov {
320 fn from(duration: Option<CuDuration>) -> Self {
321 match duration {
322 Some(duration) => Tov::Time(duration),
323 None => Tov::None,
324 }
325 }
326}
327
328impl From<CuDuration> for Tov {
329 fn from(duration: CuDuration) -> Self {
330 Tov::Time(duration)
331 }
332}
333
334#[derive(Clone, Debug)]
338pub struct RobotClock {
339 inner: Clock, ref_time: Instant, }
342
343#[derive(Debug, Clone)]
345pub struct RobotClockMock(Arc<Mock>); impl RobotClockMock {
348 pub fn increment(&self, amount: Duration) {
349 let Self(mock) = self;
350 mock.increment(amount);
351 }
352
353 pub fn decrement(&self, amount: Duration) {
356 let Self(mock) = self;
357 mock.decrement(amount);
358 }
359
360 pub fn value(&self) -> u64 {
362 let Self(mock) = self;
363 mock.value()
364 }
365
366 pub fn now(&self) -> CuTime {
368 let Self(mock) = self;
369 mock.value().into()
370 }
371
372 pub fn set_value(&self, value: u64) {
374 let Self(mock) = self;
375 let v = mock.value();
376 if v < value {
378 self.increment(Duration::from_nanos(value) - Duration::from_nanos(v));
379 } else {
380 self.decrement(Duration::from_nanos(v) - Duration::from_nanos(value));
381 }
382 }
383}
384
385impl RobotClock {
386 pub fn new() -> Self {
389 let clock = Clock::new();
390 let ref_time = clock.now();
391 RobotClock {
392 inner: clock,
393 ref_time,
394 }
395 }
396
397 pub fn from_ref_time(ref_time_ns: u64) -> Self {
399 let clock = Clock::new();
400 let ref_time = clock.now() - Duration::from_nanos(ref_time_ns);
401 RobotClock {
402 inner: Clock::new(),
403 ref_time,
404 }
405 }
406
407 pub fn mock() -> (Self, RobotClockMock) {
410 let (clock, mock) = Clock::mock();
411 let ref_time = clock.now();
412 (
413 RobotClock {
414 inner: clock,
415 ref_time,
416 },
417 RobotClockMock(mock),
418 )
419 }
420
421 #[inline]
424 pub fn now(&self) -> CuTime {
425 (self.inner.now() - self.ref_time).into()
428 }
429
430 #[inline]
432 pub fn recent(&self) -> CuTime {
433 (self.inner.recent() - self.ref_time).into()
434 }
435}
436
437impl Default for RobotClock {
438 fn default() -> Self {
439 Self::new()
440 }
441}
442
443pub trait ClockProvider {
445 fn get_clock(&self) -> RobotClock;
446}
447
448#[cfg(test)]
449mod tests {
450 use super::*;
451 #[test]
452 fn test_cuduration_comparison_operators() {
453 let a = CuDuration(100);
454 let b = CuDuration(200);
455
456 assert!(a < b);
457 assert!(b > a);
458 assert_ne!(a, b);
459 assert_eq!(a, CuDuration(100));
460 }
461
462 #[test]
463 fn test_cuduration_arithmetic_operations() {
464 let a = CuDuration(100);
465 let b = CuDuration(50);
466
467 assert_eq!(a + b, CuDuration(150));
468 assert_eq!(a - b, CuDuration(50));
469 assert_eq!(a * 2u32, CuDuration(200));
470 assert_eq!(a / 2u32, CuDuration(50));
471 }
472
473 #[test]
474 fn test_option_cutime_handling() {
475 let some_time = OptionCuTime::from(Some(CuTime::from(100u64)));
476 let none_time = OptionCuTime::none();
477
478 assert!(!some_time.is_none());
479 assert!(none_time.is_none());
480 assert_eq!(some_time.unwrap(), CuTime::from(100u64));
481 assert_eq!(
482 Option::<CuTime>::from(some_time),
483 Some(CuTime::from(100u64))
484 );
485 assert_eq!(Option::<CuTime>::from(none_time), None);
486 }
487
488 #[test]
489 fn test_mock() {
490 let (clock, mock) = RobotClock::mock();
491 assert_eq!(clock.now(), Duration::from_secs(0).into());
492 mock.increment(Duration::from_secs(1));
493 assert_eq!(clock.now(), Duration::from_secs(1).into());
494 }
495
496 #[test]
497 fn test_mock_clone() {
498 let (clock, mock) = RobotClock::mock();
499 assert_eq!(clock.now(), Duration::from_secs(0).into());
500 let clock_clone = clock.clone();
501 mock.increment(Duration::from_secs(1));
502 assert_eq!(clock_clone.now(), Duration::from_secs(1).into());
503 }
504
505 #[test]
506 fn test_robot_clock_synchronization() {
507 let (clock1, mock) = RobotClock::mock();
509 let clock2 = clock1.clone();
510
511 assert_eq!(clock1.now(), CuDuration(0));
512 assert_eq!(clock2.now(), CuDuration(0));
513
514 mock.increment(Duration::from_secs(5));
515
516 assert_eq!(clock1.now(), Duration::from_secs(5).into());
517 assert_eq!(clock2.now(), Duration::from_secs(5).into());
518 }
519
520 #[test]
521 fn test_from_ref_time() {
522 let tolerance_ms = 10;
523 let clock = RobotClock::from_ref_time(1_000_000_000);
524 assert_relative_eq!(
525 <CuDuration as Into<Duration>>::into(clock.now()).as_millis() as f64,
526 Duration::from_secs(1).as_millis() as f64,
527 epsilon = tolerance_ms as f64
528 );
529 }
530
531 #[test]
532 fn longest_duration() {
533 let maxcu = CuDuration(u64::MAX);
534 let maxd: Duration = maxcu.into();
535 assert_eq!(maxd.as_nanos(), u64::MAX as u128);
536 let s = maxd.as_secs();
537 let y = s / 60 / 60 / 24 / 365;
538 assert!(y >= 584); }
540
541 #[test]
542 fn test_some_time_arithmetics() {
543 let a: CuDuration = 10.into();
544 let b: CuDuration = 20.into();
545 let c = a + b;
546 assert_eq!(c.0, 30);
547 let d = b - a;
548 assert_eq!(d.0, 10);
549 }
550
551 #[test]
552 fn test_build_range_from_slice() {
553 let range = CuTimeRange::from(&[20.into(), 10.into(), 30.into()][..]);
554 assert_eq!(range.start, 10.into());
555 assert_eq!(range.end, 30.into());
556 }
557
558 #[test]
559 fn test_time_range_operations() {
560 let start = CuTime::from(100u64);
562 let end = CuTime::from(200u64);
563 let range = CuTimeRange { start, end };
564
565 assert_eq!(range.start, start);
566 assert_eq!(range.end, end);
567
568 let times = [
570 CuTime::from(150u64),
571 CuTime::from(120u64),
572 CuTime::from(180u64),
573 ];
574 let range_from_slice = CuTimeRange::from(×[..]);
575
576 assert_eq!(range_from_slice.start, CuTime::from(120u64));
578 assert_eq!(range_from_slice.end, CuTime::from(180u64));
579 }
580
581 #[test]
582 fn test_partial_time_range() {
583 let start = CuTime::from(100u64);
585 let end = CuTime::from(200u64);
586
587 let partial_range = PartialCuTimeRange {
588 start: OptionCuTime::from(start),
589 end: OptionCuTime::from(end),
590 };
591
592 let opt_start: Option<CuTime> = partial_range.start.into();
594 let opt_end: Option<CuTime> = partial_range.end.into();
595
596 assert_eq!(opt_start, Some(start));
597 assert_eq!(opt_end, Some(end));
598
599 let partial_undefined = PartialCuTimeRange::default();
601 assert!(partial_undefined.start.is_none());
602 assert!(partial_undefined.end.is_none());
603 }
604
605 #[test]
606 fn test_tov_conversions() {
607 let time = CuTime::from(100u64);
609
610 let tov_time: Tov = time.into();
612 assert!(matches!(tov_time, Tov::Time(_)));
613
614 if let Tov::Time(t) = tov_time {
615 assert_eq!(t, time);
616 }
617
618 let some_time = Some(time);
620 let tov_some: Tov = some_time.into();
621 assert!(matches!(tov_some, Tov::Time(_)));
622
623 let none_time: Option<CuDuration> = None;
624 let tov_none: Tov = none_time.into();
625 assert!(matches!(tov_none, Tov::None));
626
627 let start = CuTime::from(100u64);
629 let end = CuTime::from(200u64);
630 let range = CuTimeRange { start, end };
631 let tov_range = Tov::Range(range);
632
633 assert!(matches!(tov_range, Tov::Range(_)));
634 }
635
636 #[test]
637 fn test_cuduration_display() {
638 let nano = CuDuration(42);
640 assert_eq!(nano.to_string(), "42 ns");
641
642 let micro = CuDuration(42_000);
643 assert_eq!(micro.to_string(), "42.000 µs");
644
645 let milli = CuDuration(42_000_000);
646 assert_eq!(milli.to_string(), "42.000 ms");
647
648 let sec = CuDuration(1_500_000_000);
649 assert_eq!(sec.to_string(), "1.500 s");
650
651 let min = CuDuration(90_000_000_000);
652 assert_eq!(min.to_string(), "1.500 m");
653
654 let hour = CuDuration(3_600_000_000_000);
655 assert_eq!(hour.to_string(), "1.000 h");
656
657 let day = CuDuration(86_400_000_000_000);
658 assert_eq!(day.to_string(), "1.000 d");
659 }
660
661 #[test]
662 fn test_robot_clock_precision() {
663 let clock = RobotClock::new();
666
667 let recent = clock.recent();
669 let now = clock.now();
670
671 assert!(recent <= now);
673
674 let ref_time_ns = 1_000_000_000; let clock = RobotClock::from_ref_time(ref_time_ns);
677
678 let now = clock.now();
680 let now_ns: u64 = now.into();
681
682 let tolerance_ns = 50_000_000; assert!(now_ns >= ref_time_ns);
685 assert!(now_ns < ref_time_ns + tolerance_ns);
686 }
687
688 #[test]
689 fn test_mock_clock_advanced_operations() {
690 let (clock, mock) = RobotClock::mock();
692
693 assert_eq!(clock.now(), CuDuration(0));
695
696 mock.increment(Duration::from_secs(10));
698 assert_eq!(clock.now(), Duration::from_secs(10).into());
699
700 mock.decrement(Duration::from_secs(5));
702 assert_eq!(clock.now(), Duration::from_secs(5).into());
703
704 mock.set_value(30_000_000_000); assert_eq!(clock.now(), Duration::from_secs(30).into());
707
708 assert_eq!(mock.now(), Duration::from_secs(30).into());
710 assert_eq!(mock.value(), 30_000_000_000);
711 }
712
713 #[test]
714 fn test_cuduration_min_max() {
715 assert_eq!(CuDuration::MIN, CuDuration(0));
717
718 let a = CuDuration(100);
720 let b = CuDuration(200);
721
722 assert_eq!(a.min(b), a);
723 assert_eq!(a.max(b), b);
724 assert_eq!(b.min(a), a);
725 assert_eq!(b.max(a), b);
726
727 assert_eq!(a.min(a), a);
729 assert_eq!(a.max(a), a);
730
731 assert_eq!(a.min(CuDuration::MIN), CuDuration::MIN);
733 assert_eq!(a.max(CuDuration::MAX), CuDuration::MAX);
734 }
735
736 #[test]
737 fn test_clock_provider_trait() {
738 struct TestClockProvider {
740 clock: RobotClock,
741 }
742
743 impl ClockProvider for TestClockProvider {
744 fn get_clock(&self) -> RobotClock {
745 self.clock.clone()
746 }
747 }
748
749 let (clock, mock) = RobotClock::mock();
751 let provider = TestClockProvider { clock };
752
753 let provider_clock = provider.get_clock();
755 assert_eq!(provider_clock.now(), CuDuration(0));
756
757 mock.increment(Duration::from_secs(5));
759 assert_eq!(provider_clock.now(), Duration::from_secs(5).into());
760 }
761}