1use crate::{NullableHandle, ObjectQuery, Status, Topic, ok, sys};
8use std::cmp::{Eq, Ord, PartialEq, PartialOrd};
9use std::hash::Hash;
10use std::{ops, time as stdtime};
11use zerocopy::{FromBytes, Immutable, IntoBytes};
12
13pub type MonotonicInstant = Instant<MonotonicTimeline, NsUnit>;
15
16pub type SyntheticInstant = Instant<SyntheticTimeline, NsUnit>;
18
19pub type BootInstant = Instant<BootTimeline>;
21
22pub type Ticks<T> = Instant<T, TicksUnit>;
25
26pub type MonotonicTicks = Instant<MonotonicTimeline, TicksUnit>;
29
30pub type BootTicks = Instant<BootTimeline, TicksUnit>;
32
33pub type MonotonicDuration = Duration<MonotonicTimeline>;
35
36pub type BootDuration = Duration<BootTimeline>;
38
39pub type SyntheticDuration = Duration<SyntheticTimeline, NsUnit>;
41
42pub type MonotonicDurationTicks = Duration<MonotonicTimeline, TicksUnit>;
44
45pub type BootDurationTicks = Duration<BootTimeline, TicksUnit>;
47
48#[derive(
50 Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord, FromBytes, IntoBytes, Immutable,
51)]
52#[repr(transparent)]
53pub struct Instant<T, U = NsUnit>(sys::zx_time_t, std::marker::PhantomData<(T, U)>);
54
55impl<T, U> std::fmt::Debug for Instant<T, U> {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 let timeline_name = std::any::type_name::<T>();
59 let short_timeline_name =
60 timeline_name.rsplit_once("::").map(|(_, n)| n).unwrap_or(timeline_name);
61 let units_name = std::any::type_name::<U>();
62 let short_units_name = units_name.rsplit_once("::").map(|(_, n)| n).unwrap_or(units_name);
63 f.debug_tuple(&format!("Instant<{short_timeline_name}, {short_units_name}>"))
64 .field(&self.0)
65 .finish()
66 }
67}
68
69impl MonotonicInstant {
70 pub fn get() -> Self {
76 unsafe { Self::from_nanos(sys::zx_clock_get_monotonic()) }
77 }
78
79 pub fn after(duration: MonotonicDuration) -> Self {
85 unsafe { Self::from_nanos(sys::zx_deadline_after(duration.0)) }
86 }
87
88 pub fn sleep(self) {
94 unsafe {
95 sys::zx_nanosleep(self.0);
96 }
97 }
98}
99
100impl BootInstant {
101 pub fn get() -> Self {
103 unsafe { Self::from_nanos(sys::zx_clock_get_boot()) }
105 }
106
107 pub fn after(duration: BootDuration) -> Self {
109 Self::from_nanos(Self::get().into_nanos().saturating_add(duration.0))
110 }
111}
112
113impl<T: Timeline, U: TimeUnit> Instant<T, U> {
114 pub const ZERO: Instant<T, U> = Instant(0, std::marker::PhantomData);
115}
116
117impl<T: Timeline> Instant<T> {
118 pub const INFINITE: Instant<T, NsUnit> =
119 Instant(sys::ZX_TIME_INFINITE, std::marker::PhantomData);
120 pub const INFINITE_PAST: Instant<T, NsUnit> =
121 Instant(sys::ZX_TIME_INFINITE_PAST, std::marker::PhantomData);
122
123 pub const fn into_nanos(self) -> i64 {
125 self.0
126 }
127
128 pub const fn from_nanos(nanos: i64) -> Self {
130 Instant(nanos, std::marker::PhantomData)
131 }
132}
133
134impl MonotonicTicks {
135 pub fn get() -> Self {
143 Self(unsafe { sys::zx_ticks_get() }, std::marker::PhantomData)
145 }
146}
147
148impl BootTicks {
149 pub fn get() -> Self {
153 Self(unsafe { sys::zx_ticks_get_boot() }, std::marker::PhantomData)
155 }
156}
157
158impl<T: Timeline> Ticks<T> {
159 pub const fn into_raw(self) -> i64 {
161 self.0
162 }
163
164 pub const fn from_raw(raw: i64) -> Self {
166 Self(raw, std::marker::PhantomData)
167 }
168
169 pub fn per_second() -> i64 {
175 unsafe { sys::zx_ticks_per_second() }
177 }
178}
179
180impl<T: Timeline, U: TimeUnit> ops::Add<Duration<T, U>> for Instant<T, U> {
181 type Output = Instant<T, U>;
182 fn add(self, dur: Duration<T, U>) -> Self::Output {
183 Self(self.0.saturating_add(dur.0), std::marker::PhantomData)
184 }
185}
186
187impl<T: Timeline, U: TimeUnit> ops::Sub<Duration<T, U>> for Instant<T, U> {
188 type Output = Instant<T, U>;
189 fn sub(self, dur: Duration<T, U>) -> Self::Output {
190 Self(self.0.saturating_sub(dur.0), std::marker::PhantomData)
191 }
192}
193
194impl<T: Timeline, U: TimeUnit> ops::Sub<Instant<T, U>> for Instant<T, U> {
195 type Output = Duration<T, U>;
196 fn sub(self, rhs: Instant<T, U>) -> Self::Output {
197 Duration(self.0.saturating_sub(rhs.0), std::marker::PhantomData)
198 }
199}
200
201impl<T: Timeline, U: TimeUnit> ops::AddAssign<Duration<T, U>> for Instant<T, U> {
202 fn add_assign(&mut self, dur: Duration<T, U>) {
203 self.0 = self.0.saturating_add(dur.0);
204 }
205}
206
207impl<T: Timeline, U: TimeUnit> ops::SubAssign<Duration<T, U>> for Instant<T, U> {
208 fn sub_assign(&mut self, dur: Duration<T, U>) {
209 self.0 = self.0.saturating_sub(dur.0);
210 }
211}
212
213pub trait Timeline: Default + Copy + Clone + PartialEq + Eq {}
215
216#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
218pub struct MonotonicTimeline;
219impl Timeline for MonotonicTimeline {}
220
221#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
223pub struct BootTimeline;
224impl Timeline for BootTimeline {}
225
226#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
228pub struct SyntheticTimeline;
229impl Timeline for SyntheticTimeline {}
230
231pub trait TimeUnit {}
233
234#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
236pub struct NsUnit;
237impl TimeUnit for NsUnit {}
238
239#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
241pub struct TicksUnit;
242impl TimeUnit for TicksUnit {}
243
244#[derive(
245 Debug,
246 Default,
247 Copy,
248 Clone,
249 Eq,
250 PartialEq,
251 Ord,
252 PartialOrd,
253 Hash,
254 FromBytes,
255 IntoBytes,
256 Immutable,
257)]
258#[repr(transparent)]
259pub struct Duration<T, U = NsUnit>(sys::zx_duration_t, std::marker::PhantomData<(T, U)>);
260
261impl<T: Timeline> From<stdtime::Duration> for Duration<T, NsUnit> {
262 fn from(dur: stdtime::Duration) -> Self {
263 Duration::from_seconds(dur.as_secs() as i64)
264 + Duration::from_nanos(dur.subsec_nanos() as i64)
265 }
266}
267
268impl<T: Timeline, U: TimeUnit> ops::Add<Instant<T, U>> for Duration<T, U> {
269 type Output = Instant<T, U>;
270 fn add(self, time: Instant<T, U>) -> Self::Output {
271 Instant(self.0.saturating_add(time.0), std::marker::PhantomData)
272 }
273}
274
275impl<T: Timeline, U: TimeUnit> ops::Add for Duration<T, U> {
276 type Output = Duration<T, U>;
277 fn add(self, rhs: Duration<T, U>) -> Self::Output {
278 Self(self.0.saturating_add(rhs.0), std::marker::PhantomData)
279 }
280}
281
282impl<T: Timeline, U: TimeUnit> ops::Sub for Duration<T, U> {
283 type Output = Duration<T, U>;
284 fn sub(self, rhs: Duration<T, U>) -> Duration<T, U> {
285 Self(self.0.saturating_sub(rhs.0), std::marker::PhantomData)
286 }
287}
288
289impl<T: Timeline, U: TimeUnit> ops::AddAssign for Duration<T, U> {
290 fn add_assign(&mut self, rhs: Duration<T, U>) {
291 self.0 = self.0.saturating_add(rhs.0);
292 }
293}
294
295impl<T: Timeline, U: TimeUnit> ops::SubAssign for Duration<T, U> {
296 fn sub_assign(&mut self, rhs: Duration<T, U>) {
297 self.0 = self.0.saturating_sub(rhs.0);
298 }
299}
300
301impl<T: Timeline, S: Into<i64>, U: TimeUnit> ops::Mul<S> for Duration<T, U> {
302 type Output = Self;
303 fn mul(self, mul: S) -> Self {
304 Self(self.0.saturating_mul(mul.into()), std::marker::PhantomData)
305 }
306}
307
308impl<S: Into<i64>, T: Timeline, U: TimeUnit> ops::Div<S> for Duration<T, U> {
309 type Output = Self;
310 fn div(self, div: S) -> Self {
311 Self(self.0.saturating_div(div.into()), std::marker::PhantomData)
312 }
313}
314
315impl<T: Timeline, U: TimeUnit> ops::Neg for Duration<T, U> {
316 type Output = Self;
317
318 fn neg(self) -> Self::Output {
319 Self(self.0.saturating_neg(), std::marker::PhantomData)
320 }
321}
322
323impl<T: Timeline> Duration<T, NsUnit> {
324 pub const INFINITE: Duration<T> = Duration(sys::zx_duration_t::MAX, std::marker::PhantomData);
325 pub const INFINITE_PAST: Duration<T> =
326 Duration(sys::zx_duration_t::MIN, std::marker::PhantomData);
327 pub const ZERO: Duration<T> = Duration(0, std::marker::PhantomData);
328
329 pub const fn into_nanos(self) -> i64 {
331 self.0
332 }
333
334 pub const fn into_micros(self) -> i64 {
336 self.0 / 1_000
337 }
338
339 pub const fn into_millis(self) -> i64 {
341 self.into_micros() / 1_000
342 }
343
344 pub const fn into_seconds(self) -> i64 {
346 self.into_millis() / 1_000
347 }
348
349 pub fn into_seconds_f64(self) -> f64 {
351 self.into_nanos() as f64 / 1_000_000_000f64
352 }
353
354 pub const fn into_minutes(self) -> i64 {
356 self.into_seconds() / 60
357 }
358
359 pub const fn into_hours(self) -> i64 {
361 self.into_minutes() / 60
362 }
363
364 pub const fn from_nanos(nanos: i64) -> Self {
365 Duration(nanos, std::marker::PhantomData)
366 }
367
368 pub const fn from_micros(micros: i64) -> Self {
369 Duration(micros.saturating_mul(1_000), std::marker::PhantomData)
370 }
371
372 pub const fn from_millis(millis: i64) -> Self {
373 Duration::from_micros(millis.saturating_mul(1_000))
374 }
375
376 pub const fn from_seconds(secs: i64) -> Self {
377 Duration::from_millis(secs.saturating_mul(1_000))
378 }
379
380 pub const fn from_minutes(min: i64) -> Self {
381 Duration::from_seconds(min.saturating_mul(60))
382 }
383
384 pub const fn from_hours(hours: i64) -> Self {
385 Duration::from_minutes(hours.saturating_mul(60))
386 }
387}
388
389impl<T: Timeline> Duration<T, TicksUnit> {
390 pub const fn into_raw(self) -> i64 {
392 self.0
393 }
394
395 pub const fn from_raw(raw: i64) -> Self {
397 Self(raw, std::marker::PhantomData)
398 }
399}
400
401impl MonotonicDuration {
402 pub fn sleep(self) {
404 MonotonicInstant::after(self).sleep()
405 }
406}
407
408#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
413#[repr(transparent)]
414pub struct Timer<T = MonotonicTimeline>(NullableHandle, std::marker::PhantomData<T>);
416
417impl_handle_based!(Timer, [T: Timeline], [T]);
418
419#[repr(C)]
420#[derive(Debug, Copy, Clone, Eq, PartialEq, FromBytes, Immutable)]
421pub struct TimerInfo<T: Timeline> {
422 pub options: u32,
423 clock_id: u32,
428 pub deadline: Instant<T>,
429 pub slack: Duration<T>,
430}
431
432pub type MonotonicTimerInfo = TimerInfo<MonotonicTimeline>;
433pub type BootTimerInfo = TimerInfo<BootTimeline>;
434pub type SyntheticTimerInfo = TimerInfo<SyntheticTimeline>;
435
436static_assertions::assert_eq_size!(MonotonicTimerInfo, sys::zx_info_timer_t);
437static_assertions::assert_eq_size!(BootTimerInfo, sys::zx_info_timer_t);
438static_assertions::assert_eq_size!(SyntheticTimerInfo, sys::zx_info_timer_t);
439
440impl<T: Timeline> Default for TimerInfo<T> {
441 fn default() -> Self {
442 Self::from_raw(sys::zx_info_timer_t::default())
443 }
444}
445
446impl<T: Timeline> TimerInfo<T> {
447 fn from_raw(info: sys::zx_info_timer_t) -> Self {
448 zerocopy::transmute!(info)
449 }
450}
451
452struct TimerInfoQuery;
453unsafe impl ObjectQuery for TimerInfoQuery {
454 const TOPIC: Topic = Topic::TIMER;
455 type InfoTy = sys::zx_info_timer_t;
456}
457
458pub type MonotonicTimer = Timer<MonotonicTimeline>;
460
461pub type BootTimer = Timer<BootTimeline>;
463
464impl<T: Timeline> Timer<T> {
465 pub fn info(&self) -> Result<TimerInfo<T>, Status> {
469 Ok(TimerInfo::from_raw(self.0.get_info_single::<TimerInfoQuery>()?))
470 }
471}
472
473impl Timer<MonotonicTimeline> {
474 pub fn create() -> Self {
484 let mut out = 0;
485 let opts = 0;
486 let status = unsafe { sys::zx_timer_create(opts, sys::ZX_CLOCK_MONOTONIC, &mut out) };
487 ok(status)
488 .expect("timer creation always succeeds except with OOM or when job policy denies it");
489 unsafe { Self::from(NullableHandle::from_raw(out)) }
490 }
491}
492
493impl Timer<BootTimeline> {
494 pub fn create() -> Self {
506 let mut out = 0;
507 let opts = 0;
508 let status = unsafe { sys::zx_timer_create(opts, sys::ZX_CLOCK_BOOT, &mut out) };
509 ok(status)
510 .expect("timer creation always succeeds except with OOM or when job policy denies it");
511 unsafe { Self::from(NullableHandle::from_raw(out)) }
512 }
513}
514
515impl<T: Timeline> Timer<T> {
516 pub fn set(&self, deadline: Instant<T>, slack: Duration<T, NsUnit>) -> Result<(), Status> {
520 let status = unsafe {
521 sys::zx_timer_set(self.raw_handle(), deadline.into_nanos(), slack.into_nanos())
522 };
523 ok(status)
524 }
525
526 pub fn cancel(&self) -> Result<(), Status> {
530 let status = unsafe { sys::zx_timer_cancel(self.raw_handle()) };
531 ok(status)
532 }
533}
534
535#[cfg(test)]
536mod tests {
537 use super::*;
538 use crate::{Signals, WaitResult};
539
540 #[test]
541 fn time_debug_repr_is_short() {
542 assert_eq!(
543 format!("{:?}", MonotonicInstant::from_nanos(0)),
544 "Instant<MonotonicTimeline, NsUnit>(0)"
545 );
546 assert_eq!(
547 format!("{:?}", SyntheticInstant::from_nanos(0)),
548 "Instant<SyntheticTimeline, NsUnit>(0)"
549 );
550 }
551
552 #[test]
553 fn monotonic_time_increases() {
554 let time1 = MonotonicInstant::get();
555 Duration::from_nanos(1_000).sleep();
556 let time2 = MonotonicInstant::get();
557 assert!(time2 > time1);
558 }
559
560 #[test]
561 fn ticks_increases() {
562 let ticks1 = MonotonicTicks::get();
563 Duration::from_nanos(1_000).sleep();
564 let ticks2 = MonotonicTicks::get();
565 assert!(ticks2 > ticks1);
566 }
567
568 #[test]
569 fn boot_time_increases() {
570 let time1 = BootInstant::get();
571 Duration::from_nanos(1_000).sleep();
572 let time2 = BootInstant::get();
573 assert!(time2 > time1);
574 }
575
576 #[test]
577 fn boot_ticks_increases() {
578 let ticks1 = BootTicks::get();
579 Duration::from_nanos(1_000).sleep();
580 let ticks2 = BootTicks::get();
581 assert!(ticks2 > ticks1);
582 }
583
584 #[test]
585 fn tick_length() {
586 let sleep_time = Duration::from_millis(1);
587 let ticks1 = MonotonicTicks::get();
588 sleep_time.sleep();
589 let ticks2 = MonotonicTicks::get();
590
591 let sleep_ticks = MonotonicDurationTicks::from_raw(
593 sleep_time.into_millis() * (MonotonicTicks::per_second() / 1000),
594 );
595 assert!(ticks2 >= (ticks1 + sleep_ticks));
596 }
597
598 #[test]
599 fn sleep() {
600 let sleep_ns = Duration::from_millis(1);
601 let time1 = MonotonicInstant::get();
602 sleep_ns.sleep();
603 let time2 = MonotonicInstant::get();
604 assert!(time2 > time1 + sleep_ns);
605 }
606
607 #[test]
608 fn from_std() {
609 let std_dur = stdtime::Duration::new(25, 25);
610 let dur = MonotonicDuration::from(std_dur);
611 let std_dur_nanos = (1_000_000_000 * std_dur.as_secs()) + std_dur.subsec_nanos() as u64;
612 assert_eq!(std_dur_nanos as i64, dur.into_nanos());
613 }
614
615 #[test]
616 fn i64_conversions() {
617 let nanos_in_one_hour = 3_600_000_000_000;
618 let dur_from_nanos = MonotonicDuration::from_nanos(nanos_in_one_hour);
619 let dur_from_hours = MonotonicDuration::from_hours(1);
620 assert_eq!(dur_from_nanos, dur_from_hours);
621 assert_eq!(dur_from_nanos.into_nanos(), dur_from_hours.into_nanos());
622 assert_eq!(dur_from_nanos.into_nanos(), nanos_in_one_hour);
623 assert_eq!(dur_from_nanos.into_hours(), 1);
624 }
625
626 #[test]
627 fn monotonic_timer_basic() {
628 let slack = Duration::from_millis(0);
629 let ten_ms = Duration::from_millis(10);
630 let five_secs = Duration::from_seconds(5);
631
632 let timer = MonotonicTimer::create();
634
635 let info = timer.info().expect("info() failed");
636 assert_eq!(info.clock_id, sys::ZX_CLOCK_MONOTONIC);
637 assert_eq!(info.deadline, Instant::ZERO);
638 assert_eq!(
642 timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
643 WaitResult::TimedOut(Signals::empty()),
644 );
645
646 let instant = MonotonicInstant::after(five_secs);
648 assert_eq!(timer.set(instant, slack), Ok(()));
649 assert_eq!(
650 timer.wait_one(Signals::TIMER_SIGNALED, Instant::INFINITE),
651 WaitResult::Ok(Signals::TIMER_SIGNALED)
652 );
653 assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
655
656 assert_eq!(timer.cancel(), Ok(()));
658 assert_eq!(
659 timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
660 WaitResult::TimedOut(Signals::empty()),
661 );
662 assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
663
664 assert_eq!(timer.set(Instant::INFINITE, slack), Ok(()));
665 assert_eq!(timer.info().expect("info() failed").deadline, Instant::INFINITE);
666 }
667
668 #[test]
669 fn boot_timer_basic() {
670 let slack = Duration::from_millis(0);
671 let ten_ms = Duration::from_millis(10);
672 let five_secs = Duration::from_seconds(5);
673
674 let timer = BootTimer::create();
676
677 let info = timer.info().expect("info() failed");
678 assert_eq!(info.clock_id, sys::ZX_CLOCK_BOOT);
679 assert_eq!(info.deadline, Instant::ZERO);
680 assert_eq!(
684 timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
685 WaitResult::TimedOut(Signals::empty())
686 );
687
688 let instant = BootInstant::after(five_secs);
690 assert_eq!(timer.set(instant, slack), Ok(()));
691 assert_eq!(
692 timer.wait_one(Signals::TIMER_SIGNALED, Instant::INFINITE),
693 WaitResult::Ok(Signals::TIMER_SIGNALED)
694 );
695 assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
697
698 assert_eq!(timer.cancel(), Ok(()));
700 assert_eq!(
701 timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
702 WaitResult::TimedOut(Signals::empty())
703 );
704 assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
705
706 assert_eq!(timer.set(Instant::INFINITE, slack), Ok(()));
707 assert_eq!(timer.info().expect("info() failed").deadline, Instant::INFINITE);
708 }
709
710 #[test]
711 fn time_minus_time() {
712 let lhs = MonotonicInstant::from_nanos(10);
713 let rhs = MonotonicInstant::from_nanos(30);
714 assert_eq!(lhs - rhs, Duration::from_nanos(-20));
715 }
716
717 #[test]
718 fn time_saturation() {
719 assert_eq!(
721 MonotonicInstant::from_nanos(10) + Duration::from_nanos(30),
722 MonotonicInstant::from_nanos(40)
723 );
724 assert_eq!(
725 MonotonicInstant::from_nanos(10) + Duration::INFINITE,
726 MonotonicInstant::INFINITE
727 );
728 assert_eq!(
729 MonotonicInstant::from_nanos(-10) + Duration::INFINITE_PAST,
730 MonotonicInstant::INFINITE_PAST
731 );
732
733 assert_eq!(
735 MonotonicInstant::from_nanos(10) - Duration::from_nanos(30),
736 MonotonicInstant::from_nanos(-20)
737 );
738 assert_eq!(
739 MonotonicInstant::from_nanos(-10) - Duration::INFINITE,
740 MonotonicInstant::INFINITE_PAST
741 );
742 assert_eq!(
743 MonotonicInstant::from_nanos(10) - Duration::INFINITE_PAST,
744 MonotonicInstant::INFINITE
745 );
746
747 {
749 let mut t = MonotonicInstant::from_nanos(10);
750 t += Duration::from_nanos(30);
751 assert_eq!(t, MonotonicInstant::from_nanos(40));
752 }
753 {
754 let mut t = MonotonicInstant::from_nanos(10);
755 t += Duration::INFINITE;
756 assert_eq!(t, MonotonicInstant::INFINITE);
757 }
758 {
759 let mut t = MonotonicInstant::from_nanos(-10);
760 t += Duration::INFINITE_PAST;
761 assert_eq!(t, MonotonicInstant::INFINITE_PAST);
762 }
763
764 {
766 let mut t = MonotonicInstant::from_nanos(10);
767 t -= Duration::from_nanos(30);
768 assert_eq!(t, MonotonicInstant::from_nanos(-20));
769 }
770 {
771 let mut t = MonotonicInstant::from_nanos(-10);
772 t -= Duration::INFINITE;
773 assert_eq!(t, MonotonicInstant::INFINITE_PAST);
774 }
775 {
776 let mut t = MonotonicInstant::from_nanos(10);
777 t -= Duration::INFINITE_PAST;
778 assert_eq!(t, MonotonicInstant::INFINITE);
779 }
780 }
781
782 #[test]
783 fn duration_saturation() {
784 assert_eq!(
786 MonotonicDuration::from_nanos(10) + Duration::from_nanos(30),
787 Duration::from_nanos(40)
788 );
789 assert_eq!(MonotonicDuration::from_nanos(10) + Duration::INFINITE, Duration::INFINITE);
790 assert_eq!(
791 MonotonicDuration::from_nanos(-10) + Duration::INFINITE_PAST,
792 Duration::INFINITE_PAST
793 );
794
795 assert_eq!(
797 MonotonicDuration::from_nanos(10) - Duration::from_nanos(30),
798 Duration::from_nanos(-20)
799 );
800 assert_eq!(
801 MonotonicDuration::from_nanos(-10) - Duration::INFINITE,
802 Duration::INFINITE_PAST
803 );
804 assert_eq!(MonotonicDuration::from_nanos(10) - Duration::INFINITE_PAST, Duration::INFINITE);
805
806 assert_eq!(MonotonicDuration::from_nanos(10) * 3, Duration::from_nanos(30));
808 assert_eq!(MonotonicDuration::from_nanos(10) * i64::MAX, Duration::INFINITE);
809 assert_eq!(MonotonicDuration::from_nanos(10) * i64::MIN, Duration::INFINITE_PAST);
810
811 assert_eq!(MonotonicDuration::from_nanos(30) / 3, Duration::from_nanos(10));
813 assert_eq!(MonotonicDuration::INFINITE_PAST / -1, Duration::INFINITE);
814
815 assert_eq!(-MonotonicDuration::from_nanos(30), Duration::from_nanos(-30));
817 assert_eq!(-MonotonicDuration::INFINITE_PAST, Duration::INFINITE);
818
819 {
821 let mut t = MonotonicDuration::from_nanos(10);
822 t += Duration::from_nanos(30);
823 assert_eq!(t, Duration::from_nanos(40));
824 }
825 {
826 let mut t = MonotonicDuration::from_nanos(10);
827 t += Duration::INFINITE;
828 assert_eq!(t, Duration::INFINITE);
829 }
830 {
831 let mut t = MonotonicDuration::from_nanos(-10);
832 t += Duration::INFINITE_PAST;
833 assert_eq!(t, Duration::INFINITE_PAST);
834 }
835
836 {
838 let mut t = MonotonicDuration::from_nanos(10);
839 t -= Duration::from_nanos(30);
840 assert_eq!(t, Duration::from_nanos(-20));
841 }
842 {
843 let mut t = MonotonicDuration::from_nanos(-10);
844 t -= Duration::INFINITE;
845 assert_eq!(t, Duration::INFINITE_PAST);
846 }
847 {
848 let mut t = MonotonicDuration::from_nanos(10);
849 t -= Duration::INFINITE_PAST;
850 assert_eq!(t, Duration::INFINITE);
851 }
852 }
853
854 #[test]
855 fn time_minus_time_saturates() {
856 assert_eq!(
857 MonotonicInstant::INFINITE - MonotonicInstant::INFINITE_PAST,
858 Duration::INFINITE
859 );
860 }
861
862 #[test]
863 fn time_and_duration_defaults() {
864 assert_eq!(MonotonicInstant::default(), MonotonicInstant::from_nanos(0));
865 assert_eq!(Duration::default(), MonotonicDuration::from_nanos(0));
866 }
867}