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}