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