vexide_core/time.rs
1//! Temporal quantification.
2//!
3//! This module provides an implementation of [`Instant`] built on the VEXos high-resolution timer.
4
5use core::{
6 fmt,
7 ops::{Add, AddAssign, Sub, SubAssign},
8 time::Duration,
9};
10
11use vex_sdk::vexSystemPowerupTimeGet;
12
13/// Represents a timestamp on a monotonically nondecreasing clock relative to the
14/// start of the user program.
15///
16/// # Precision
17/// This type has a precision of 1 microsecond, and uses [`vex_sdk::vexSystemHighResTimeGet`] internally.
18#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct Instant(u64);
20
21impl Instant {
22 /// Returns an instant corresponding to "now".
23 ///
24 /// # Examples
25 ///
26 /// ```
27 /// use vexide::time::Instant;
28 ///
29 /// let now = Instant::now();
30 /// ```
31 #[must_use]
32 pub fn now() -> Self {
33 Self(unsafe { vex_sdk::vexSystemHighResTimeGet() })
34 }
35
36 /// Returns the amount of time elapsed from another instant to this one,
37 /// or zero duration if that instant is later than this one.
38 ///
39 /// # Examples
40 ///
41 /// ```no_run
42 /// use core::time::Duration;
43 /// use vexide::time::Instant;
44 ///
45 /// let now = Instant::now();
46 /// sleep(Duration::new(1, 0)).await;
47 /// let new_now = Instant::now();
48 /// println!("{:?}", new_now.duration_since(now));
49 /// println!("{:?}", now.duration_since(new_now)); // 0ns
50 /// ```
51 #[must_use]
52 pub fn duration_since(&self, earlier: Instant) -> Duration {
53 self.checked_duration_since(earlier).unwrap_or_default()
54 }
55
56 /// Returns the amount of time elapsed from another instant to this one,
57 /// or None if that instant is later than this one.
58 ///
59 /// # Examples
60 ///
61 /// ```no_run
62 /// use core::time::Duration;
63 /// use vexide::time::Instant;
64 ///
65 /// let now = Instant::now();
66 /// sleep(Duration::new(1, 0)).await;
67 /// let new_now = Instant::now();
68 /// println!("{:?}", new_now.checked_duration_since(now));
69 /// println!("{:?}", now.checked_duration_since(new_now)); // None
70 /// ```
71 #[must_use]
72 pub const fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
73 if earlier.0 < self.0 {
74 Some(Duration::from_micros(self.0 - earlier.0))
75 } else {
76 None
77 }
78 }
79
80 /// Returns the amount of time elapsed from another instant to this one,
81 /// or zero duration if that instant is later than this one.
82 ///
83 /// # Examples
84 ///
85 /// ```no_run
86 /// use core::time::Duration;
87 /// use vexide::time::Instant;
88 ///
89 /// let now = Instant::now();
90 /// sleep(Duration::new(1, 0)).await;
91 /// let new_now = Instant::now();
92 /// println!("{:?}", new_now.saturating_duration_since(now));
93 /// println!("{:?}", now.saturating_duration_since(new_now)); // 0ns
94 /// ```
95 #[must_use]
96 pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
97 self.checked_duration_since(earlier).unwrap_or_default()
98 }
99
100 /// Returns the amount of time elapsed since this instant.
101 ///
102 /// # Examples
103 ///
104 /// ```no_run
105 /// use core::time::Duration;
106 /// use vexide::time::Instant;
107 ///
108 /// let instant = Instant::now();
109 /// let three_secs = Duration::from_secs(3);
110 /// sleep(three_secs).await;
111 /// assert!(instant.elapsed() >= three_secs);
112 /// ```
113 #[must_use]
114 pub fn elapsed(&self) -> Duration {
115 Instant::now() - *self
116 }
117
118 /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
119 /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
120 /// otherwise.
121 #[must_use]
122 pub fn checked_add(self, rhs: Duration) -> Option<Instant> {
123 Some(Self(self.0.checked_add(rhs.as_micros().try_into().ok()?)?))
124 }
125
126 /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
127 /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
128 /// otherwise.
129 #[must_use]
130 pub fn checked_sub(self, rhs: Duration) -> Option<Instant> {
131 Some(Self(self.0.checked_sub(rhs.as_micros().try_into().ok()?)?))
132 }
133}
134
135impl Add<Duration> for Instant {
136 type Output = Instant;
137
138 /// # Panics
139 ///
140 /// This function may panic if the resulting point in time cannot be represented by the
141 /// underlying data structure. See [`Instant::checked_add`] for a version without panic.
142 fn add(self, rhs: Duration) -> Self::Output {
143 self.checked_add(rhs)
144 .expect("overflow when adding duration to instant")
145 }
146}
147
148impl AddAssign<Duration> for Instant {
149 fn add_assign(&mut self, other: Duration) {
150 *self = *self + other;
151 }
152}
153
154impl Sub<Duration> for Instant {
155 type Output = Instant;
156
157 fn sub(self, other: Duration) -> Instant {
158 self.checked_sub(other)
159 .expect("overflow when subtracting duration from instant")
160 }
161}
162
163impl SubAssign<Duration> for Instant {
164 fn sub_assign(&mut self, other: Duration) {
165 *self = *self - other;
166 }
167}
168
169impl Sub<Instant> for Instant {
170 type Output = Duration;
171
172 /// Returns the amount of time elapsed from another instant to this one,
173 /// or zero duration if that instant is later than this one.
174 fn sub(self, other: Instant) -> Duration {
175 self.duration_since(other)
176 }
177}
178
179impl fmt::Debug for Instant {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 self.0.fmt(f)
182 }
183}
184
185/// Returns the duration that the brain has been turned on.
186#[must_use]
187pub fn uptime() -> Duration {
188 Duration::from_micros(unsafe { vexSystemPowerupTimeGet() })
189}