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
458#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
463pub enum TimerSlackMode {
464 #[default]
466 Center,
467 Early,
469 Late,
471}
472
473impl From<TimerSlackMode> for u32 {
474 fn from(mode: TimerSlackMode) -> u32 {
475 match mode {
476 TimerSlackMode::Center => sys::ZX_TIMER_SLACK_CENTER,
477 TimerSlackMode::Early => sys::ZX_TIMER_SLACK_EARLY,
478 TimerSlackMode::Late => sys::ZX_TIMER_SLACK_LATE,
479 }
480 }
481}
482
483pub type MonotonicTimer = Timer<MonotonicTimeline>;
485
486pub type BootTimer = Timer<BootTimeline>;
488
489impl<T: Timeline> Timer<T> {
490 pub fn info(&self) -> Result<TimerInfo<T>, Status> {
494 Ok(TimerInfo::from_raw(self.0.get_info_single::<TimerInfoQuery>()?))
495 }
496}
497
498impl Timer<MonotonicTimeline> {
499 pub fn create() -> Self {
509 Self::create_with_slack_mode(TimerSlackMode::Center)
510 }
511
512 pub fn create_with_slack_mode(mode: TimerSlackMode) -> Self {
522 let mut out = 0;
523 let opts = mode.into();
524 let status = unsafe { sys::zx_timer_create(opts, sys::ZX_CLOCK_MONOTONIC, &mut out) };
525 ok(status)
526 .expect("timer creation always succeeds except with OOM or when job policy denies it");
527 unsafe { Self::from(NullableHandle::from_raw(out)) }
528 }
529}
530
531impl Timer<BootTimeline> {
532 pub fn create() -> Self {
544 Self::create_with_slack_mode(TimerSlackMode::Center)
545 }
546
547 pub fn create_with_slack_mode(mode: TimerSlackMode) -> Self {
559 let mut out = 0;
560 let opts = mode.into();
561 let status = unsafe { sys::zx_timer_create(opts, sys::ZX_CLOCK_BOOT, &mut out) };
562 ok(status)
563 .expect("timer creation always succeeds except with OOM or when job policy denies it");
564 unsafe { Self::from(NullableHandle::from_raw(out)) }
565 }
566}
567
568impl<T: Timeline> Timer<T> {
569 pub fn set(&self, deadline: Instant<T>, slack: Duration<T, NsUnit>) -> Result<(), Status> {
573 let status = unsafe {
574 sys::zx_timer_set(self.raw_handle(), deadline.into_nanos(), slack.into_nanos())
575 };
576 ok(status)
577 }
578
579 pub fn cancel(&self) -> Result<(), Status> {
583 let status = unsafe { sys::zx_timer_cancel(self.raw_handle()) };
584 ok(status)
585 }
586}
587
588#[cfg(test)]
589mod tests {
590 use super::*;
591 use crate::{Signals, WaitResult};
592
593 #[test]
594 fn time_debug_repr_is_short() {
595 assert_eq!(
596 format!("{:?}", MonotonicInstant::from_nanos(0)),
597 "Instant<MonotonicTimeline, NsUnit>(0)"
598 );
599 assert_eq!(
600 format!("{:?}", SyntheticInstant::from_nanos(0)),
601 "Instant<SyntheticTimeline, NsUnit>(0)"
602 );
603 }
604
605 #[test]
606 fn monotonic_time_increases() {
607 let time1 = MonotonicInstant::get();
608 Duration::from_nanos(1_000).sleep();
609 let time2 = MonotonicInstant::get();
610 assert!(time2 > time1);
611 }
612
613 #[test]
614 fn ticks_increases() {
615 let ticks1 = MonotonicTicks::get();
616 Duration::from_nanos(1_000).sleep();
617 let ticks2 = MonotonicTicks::get();
618 assert!(ticks2 > ticks1);
619 }
620
621 #[test]
622 fn boot_time_increases() {
623 let time1 = BootInstant::get();
624 Duration::from_nanos(1_000).sleep();
625 let time2 = BootInstant::get();
626 assert!(time2 > time1);
627 }
628
629 #[test]
630 fn boot_ticks_increases() {
631 let ticks1 = BootTicks::get();
632 Duration::from_nanos(1_000).sleep();
633 let ticks2 = BootTicks::get();
634 assert!(ticks2 > ticks1);
635 }
636
637 #[test]
638 fn tick_length() {
639 let sleep_time = Duration::from_millis(1);
640 let ticks1 = MonotonicTicks::get();
641 sleep_time.sleep();
642 let ticks2 = MonotonicTicks::get();
643
644 let sleep_ticks = MonotonicDurationTicks::from_raw(
646 sleep_time.into_millis() * (MonotonicTicks::per_second() / 1000),
647 );
648 assert!(ticks2 >= (ticks1 + sleep_ticks));
649 }
650
651 #[test]
652 fn sleep() {
653 let sleep_ns = Duration::from_millis(1);
654 let time1 = MonotonicInstant::get();
655 sleep_ns.sleep();
656 let time2 = MonotonicInstant::get();
657 assert!(time2 > time1 + sleep_ns);
658 }
659
660 #[test]
661 fn from_std() {
662 let std_dur = stdtime::Duration::new(25, 25);
663 let dur = MonotonicDuration::from(std_dur);
664 let std_dur_nanos = (1_000_000_000 * std_dur.as_secs()) + std_dur.subsec_nanos() as u64;
665 assert_eq!(std_dur_nanos as i64, dur.into_nanos());
666 }
667
668 #[test]
669 fn i64_conversions() {
670 let nanos_in_one_hour = 3_600_000_000_000;
671 let dur_from_nanos = MonotonicDuration::from_nanos(nanos_in_one_hour);
672 let dur_from_hours = MonotonicDuration::from_hours(1);
673 assert_eq!(dur_from_nanos, dur_from_hours);
674 assert_eq!(dur_from_nanos.into_nanos(), dur_from_hours.into_nanos());
675 assert_eq!(dur_from_nanos.into_nanos(), nanos_in_one_hour);
676 assert_eq!(dur_from_nanos.into_hours(), 1);
677 }
678
679 #[test]
680 fn monotonic_timer_basic() {
681 let slack = Duration::from_millis(0);
682 let ten_ms = Duration::from_millis(10);
683 let five_secs = Duration::from_seconds(5);
684
685 let timer = MonotonicTimer::create();
687
688 let info = timer.info().expect("info() failed");
689 assert_eq!(info.clock_id, sys::ZX_CLOCK_MONOTONIC);
690 assert_eq!(info.deadline, Instant::ZERO);
691 assert_eq!(
695 timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
696 WaitResult::TimedOut(Signals::empty()),
697 );
698
699 let instant = MonotonicInstant::after(five_secs);
701 assert_eq!(timer.set(instant, slack), Ok(()));
702 assert_eq!(
703 timer.wait_one(Signals::TIMER_SIGNALED, Instant::INFINITE),
704 WaitResult::Ok(Signals::TIMER_SIGNALED)
705 );
706 assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
708
709 assert_eq!(timer.cancel(), Ok(()));
711 assert_eq!(
712 timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
713 WaitResult::TimedOut(Signals::empty()),
714 );
715 assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
716
717 assert_eq!(timer.set(Instant::INFINITE, slack), Ok(()));
718 assert_eq!(timer.info().expect("info() failed").deadline, Instant::INFINITE);
719 }
720
721 #[test]
722 fn boot_timer_basic() {
723 let slack = Duration::from_millis(0);
724 let ten_ms = Duration::from_millis(10);
725 let five_secs = Duration::from_seconds(5);
726
727 let timer = BootTimer::create();
729
730 let info = timer.info().expect("info() failed");
731 assert_eq!(info.clock_id, sys::ZX_CLOCK_BOOT);
732 assert_eq!(info.deadline, Instant::ZERO);
733 assert_eq!(
737 timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
738 WaitResult::TimedOut(Signals::empty())
739 );
740
741 let instant = BootInstant::after(five_secs);
743 assert_eq!(timer.set(instant, slack), Ok(()));
744 assert_eq!(
745 timer.wait_one(Signals::TIMER_SIGNALED, Instant::INFINITE),
746 WaitResult::Ok(Signals::TIMER_SIGNALED)
747 );
748 assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
750
751 assert_eq!(timer.cancel(), Ok(()));
753 assert_eq!(
754 timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
755 WaitResult::TimedOut(Signals::empty())
756 );
757 assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
758
759 assert_eq!(timer.set(Instant::INFINITE, slack), Ok(()));
760 assert_eq!(timer.info().expect("info() failed").deadline, Instant::INFINITE);
761 }
762
763 #[test]
764 fn time_minus_time() {
765 let lhs = MonotonicInstant::from_nanos(10);
766 let rhs = MonotonicInstant::from_nanos(30);
767 assert_eq!(lhs - rhs, Duration::from_nanos(-20));
768 }
769
770 #[test]
771 fn time_saturation() {
772 assert_eq!(
774 MonotonicInstant::from_nanos(10) + Duration::from_nanos(30),
775 MonotonicInstant::from_nanos(40)
776 );
777 assert_eq!(
778 MonotonicInstant::from_nanos(10) + Duration::INFINITE,
779 MonotonicInstant::INFINITE
780 );
781 assert_eq!(
782 MonotonicInstant::from_nanos(-10) + Duration::INFINITE_PAST,
783 MonotonicInstant::INFINITE_PAST
784 );
785
786 assert_eq!(
788 MonotonicInstant::from_nanos(10) - Duration::from_nanos(30),
789 MonotonicInstant::from_nanos(-20)
790 );
791 assert_eq!(
792 MonotonicInstant::from_nanos(-10) - Duration::INFINITE,
793 MonotonicInstant::INFINITE_PAST
794 );
795 assert_eq!(
796 MonotonicInstant::from_nanos(10) - Duration::INFINITE_PAST,
797 MonotonicInstant::INFINITE
798 );
799
800 {
802 let mut t = MonotonicInstant::from_nanos(10);
803 t += Duration::from_nanos(30);
804 assert_eq!(t, MonotonicInstant::from_nanos(40));
805 }
806 {
807 let mut t = MonotonicInstant::from_nanos(10);
808 t += Duration::INFINITE;
809 assert_eq!(t, MonotonicInstant::INFINITE);
810 }
811 {
812 let mut t = MonotonicInstant::from_nanos(-10);
813 t += Duration::INFINITE_PAST;
814 assert_eq!(t, MonotonicInstant::INFINITE_PAST);
815 }
816
817 {
819 let mut t = MonotonicInstant::from_nanos(10);
820 t -= Duration::from_nanos(30);
821 assert_eq!(t, MonotonicInstant::from_nanos(-20));
822 }
823 {
824 let mut t = MonotonicInstant::from_nanos(-10);
825 t -= Duration::INFINITE;
826 assert_eq!(t, MonotonicInstant::INFINITE_PAST);
827 }
828 {
829 let mut t = MonotonicInstant::from_nanos(10);
830 t -= Duration::INFINITE_PAST;
831 assert_eq!(t, MonotonicInstant::INFINITE);
832 }
833 }
834
835 #[test]
836 fn duration_saturation() {
837 assert_eq!(
839 MonotonicDuration::from_nanos(10) + Duration::from_nanos(30),
840 Duration::from_nanos(40)
841 );
842 assert_eq!(MonotonicDuration::from_nanos(10) + Duration::INFINITE, Duration::INFINITE);
843 assert_eq!(
844 MonotonicDuration::from_nanos(-10) + Duration::INFINITE_PAST,
845 Duration::INFINITE_PAST
846 );
847
848 assert_eq!(
850 MonotonicDuration::from_nanos(10) - Duration::from_nanos(30),
851 Duration::from_nanos(-20)
852 );
853 assert_eq!(
854 MonotonicDuration::from_nanos(-10) - Duration::INFINITE,
855 Duration::INFINITE_PAST
856 );
857 assert_eq!(MonotonicDuration::from_nanos(10) - Duration::INFINITE_PAST, Duration::INFINITE);
858
859 assert_eq!(MonotonicDuration::from_nanos(10) * 3, Duration::from_nanos(30));
861 assert_eq!(MonotonicDuration::from_nanos(10) * i64::MAX, Duration::INFINITE);
862 assert_eq!(MonotonicDuration::from_nanos(10) * i64::MIN, Duration::INFINITE_PAST);
863
864 assert_eq!(MonotonicDuration::from_nanos(30) / 3, Duration::from_nanos(10));
866 assert_eq!(MonotonicDuration::INFINITE_PAST / -1, Duration::INFINITE);
867
868 assert_eq!(-MonotonicDuration::from_nanos(30), Duration::from_nanos(-30));
870 assert_eq!(-MonotonicDuration::INFINITE_PAST, Duration::INFINITE);
871
872 {
874 let mut t = MonotonicDuration::from_nanos(10);
875 t += Duration::from_nanos(30);
876 assert_eq!(t, Duration::from_nanos(40));
877 }
878 {
879 let mut t = MonotonicDuration::from_nanos(10);
880 t += Duration::INFINITE;
881 assert_eq!(t, Duration::INFINITE);
882 }
883 {
884 let mut t = MonotonicDuration::from_nanos(-10);
885 t += Duration::INFINITE_PAST;
886 assert_eq!(t, Duration::INFINITE_PAST);
887 }
888
889 {
891 let mut t = MonotonicDuration::from_nanos(10);
892 t -= Duration::from_nanos(30);
893 assert_eq!(t, Duration::from_nanos(-20));
894 }
895 {
896 let mut t = MonotonicDuration::from_nanos(-10);
897 t -= Duration::INFINITE;
898 assert_eq!(t, Duration::INFINITE_PAST);
899 }
900 {
901 let mut t = MonotonicDuration::from_nanos(10);
902 t -= Duration::INFINITE_PAST;
903 assert_eq!(t, Duration::INFINITE);
904 }
905 }
906
907 #[test]
908 fn time_minus_time_saturates() {
909 assert_eq!(
910 MonotonicInstant::INFINITE - MonotonicInstant::INFINITE_PAST,
911 Duration::INFINITE
912 );
913 }
914
915 #[test]
916 fn time_and_duration_defaults() {
917 assert_eq!(MonotonicInstant::default(), MonotonicInstant::from_nanos(0));
918 assert_eq!(Duration::default(), MonotonicDuration::from_nanos(0));
919 }
920
921 #[test]
922 fn timer_create_with_slack_mode() {
923 for (mode, expected_opt) in [
924 (TimerSlackMode::Center, sys::ZX_TIMER_SLACK_CENTER),
925 (TimerSlackMode::Early, sys::ZX_TIMER_SLACK_EARLY),
926 (TimerSlackMode::Late, sys::ZX_TIMER_SLACK_LATE),
927 ] {
928 let mono = MonotonicTimer::create_with_slack_mode(mode);
929 assert_eq!(mono.info().expect("info() failed").options, expected_opt);
930
931 let boot = BootTimer::create_with_slack_mode(mode);
932 assert_eq!(boot.info().expect("info() failed").options, expected_opt);
933 }
934 }
935}