summaryrefslogtreecommitdiffstats
path: root/third_party/rust/time/src/instant.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/time/src/instant.rs')
-rw-r--r--third_party/rust/time/src/instant.rs262
1 files changed, 262 insertions, 0 deletions
diff --git a/third_party/rust/time/src/instant.rs b/third_party/rust/time/src/instant.rs
new file mode 100644
index 0000000000..2d2f65eefb
--- /dev/null
+++ b/third_party/rust/time/src/instant.rs
@@ -0,0 +1,262 @@
+//! The [`Instant`] struct and its associated `impl`s.
+
+use core::borrow::Borrow;
+use core::cmp::{Ord, Ordering, PartialEq, PartialOrd};
+use core::ops::{Add, Sub};
+use core::time::Duration as StdDuration;
+use std::time::Instant as StdInstant;
+
+use crate::Duration;
+
+/// A measurement of a monotonically non-decreasing clock. Opaque and useful only with [`Duration`].
+///
+/// Instants are always guaranteed to be no less than any previously measured instant when created,
+/// and are often useful for tasks such as measuring benchmarks or timing how long an operation
+/// takes.
+///
+/// Note, however, that instants are not guaranteed to be **steady**. In other words, each tick of
+/// the underlying clock may not be the same length (e.g. some seconds may be longer than others).
+/// An instant may jump forwards or experience time dilation (slow down or speed up), but it will
+/// never go backwards.
+///
+/// Instants are opaque types that can only be compared to one another. There is no method to get
+/// "the number of seconds" from an instant. Instead, it only allows measuring the duration between
+/// two instants (or comparing two instants).
+///
+/// This implementation allows for operations with signed [`Duration`]s, but is otherwise identical
+/// to [`std::time::Instant`].
+#[repr(transparent)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Instant(pub StdInstant);
+
+impl Instant {
+ // region: delegation
+ /// Returns an `Instant` corresponding to "now".
+ ///
+ /// ```rust
+ /// # use time::Instant;
+ /// println!("{:?}", Instant::now());
+ /// ```
+ pub fn now() -> Self {
+ Self(StdInstant::now())
+ }
+
+ /// Returns the amount of time elapsed since this instant was created. The duration will always
+ /// be nonnegative if the instant is not synthetically created.
+ ///
+ /// ```rust
+ /// # use time::{Instant, ext::{NumericalStdDuration, NumericalDuration}};
+ /// # use std::thread;
+ /// let instant = Instant::now();
+ /// thread::sleep(1.std_milliseconds());
+ /// assert!(instant.elapsed() >= 1.milliseconds());
+ /// ```
+ pub fn elapsed(self) -> Duration {
+ Self::now() - self
+ }
+ // endregion delegation
+
+ // region: checked arithmetic
+ /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
+ /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ ///
+ /// ```rust
+ /// # use time::{Instant, ext::NumericalDuration};
+ /// let now = Instant::now();
+ /// assert_eq!(now.checked_add(5.seconds()), Some(now + 5.seconds()));
+ /// assert_eq!(now.checked_add((-5).seconds()), Some(now + (-5).seconds()));
+ /// ```
+ pub fn checked_add(self, duration: Duration) -> Option<Self> {
+ if duration.is_zero() {
+ Some(self)
+ } else if duration.is_positive() {
+ self.0.checked_add(duration.unsigned_abs()).map(Self)
+ } else {
+ debug_assert!(duration.is_negative());
+ self.0.checked_sub(duration.unsigned_abs()).map(Self)
+ }
+ }
+
+ /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
+ /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ ///
+ /// ```rust
+ /// # use time::{Instant, ext::NumericalDuration};
+ /// let now = Instant::now();
+ /// assert_eq!(now.checked_sub(5.seconds()), Some(now - 5.seconds()));
+ /// assert_eq!(now.checked_sub((-5).seconds()), Some(now - (-5).seconds()));
+ /// ```
+ pub fn checked_sub(self, duration: Duration) -> Option<Self> {
+ if duration.is_zero() {
+ Some(self)
+ } else if duration.is_positive() {
+ self.0.checked_sub(duration.unsigned_abs()).map(Self)
+ } else {
+ debug_assert!(duration.is_negative());
+ self.0.checked_add(duration.unsigned_abs()).map(Self)
+ }
+ }
+ // endregion checked arithmetic
+
+ /// Obtain the inner [`std::time::Instant`].
+ ///
+ /// ```rust
+ /// # use time::Instant;
+ /// let now = Instant::now();
+ /// assert_eq!(now.into_inner(), now.0);
+ /// ```
+ pub const fn into_inner(self) -> StdInstant {
+ self.0
+ }
+}
+
+// region: trait impls
+impl From<StdInstant> for Instant {
+ fn from(instant: StdInstant) -> Self {
+ Self(instant)
+ }
+}
+
+impl From<Instant> for StdInstant {
+ fn from(instant: Instant) -> Self {
+ instant.0
+ }
+}
+
+impl Sub for Instant {
+ type Output = Duration;
+
+ fn sub(self, other: Self) -> Self::Output {
+ match self.0.cmp(&other.0) {
+ Ordering::Equal => Duration::ZERO,
+ Ordering::Greater => (self.0 - other.0)
+ .try_into()
+ .expect("overflow converting `std::time::Duration` to `time::Duration`"),
+ Ordering::Less => -Duration::try_from(other.0 - self.0)
+ .expect("overflow converting `std::time::Duration` to `time::Duration`"),
+ }
+ }
+}
+
+impl Sub<StdInstant> for Instant {
+ type Output = Duration;
+
+ fn sub(self, other: StdInstant) -> Self::Output {
+ self - Self(other)
+ }
+}
+
+impl Sub<Instant> for StdInstant {
+ type Output = Duration;
+
+ fn sub(self, other: Instant) -> Self::Output {
+ Instant(self) - other
+ }
+}
+
+impl Add<Duration> for Instant {
+ type Output = Self;
+
+ fn add(self, duration: Duration) -> Self::Output {
+ if duration.is_positive() {
+ Self(self.0 + duration.unsigned_abs())
+ } else if duration.is_negative() {
+ Self(self.0 - duration.unsigned_abs())
+ } else {
+ debug_assert!(duration.is_zero());
+ self
+ }
+ }
+}
+
+impl Add<Duration> for StdInstant {
+ type Output = Self;
+
+ fn add(self, duration: Duration) -> Self::Output {
+ (Instant(self) + duration).0
+ }
+}
+
+impl Add<StdDuration> for Instant {
+ type Output = Self;
+
+ fn add(self, duration: StdDuration) -> Self::Output {
+ Self(self.0 + duration)
+ }
+}
+
+impl_add_assign!(Instant: Duration, StdDuration);
+impl_add_assign!(StdInstant: Duration);
+
+impl Sub<Duration> for Instant {
+ type Output = Self;
+
+ fn sub(self, duration: Duration) -> Self::Output {
+ if duration.is_positive() {
+ Self(self.0 - duration.unsigned_abs())
+ } else if duration.is_negative() {
+ Self(self.0 + duration.unsigned_abs())
+ } else {
+ debug_assert!(duration.is_zero());
+ self
+ }
+ }
+}
+
+impl Sub<Duration> for StdInstant {
+ type Output = Self;
+
+ fn sub(self, duration: Duration) -> Self::Output {
+ (Instant(self) - duration).0
+ }
+}
+
+impl Sub<StdDuration> for Instant {
+ type Output = Self;
+
+ fn sub(self, duration: StdDuration) -> Self::Output {
+ Self(self.0 - duration)
+ }
+}
+
+impl_sub_assign!(Instant: Duration, StdDuration);
+impl_sub_assign!(StdInstant: Duration);
+
+impl PartialEq<StdInstant> for Instant {
+ fn eq(&self, rhs: &StdInstant) -> bool {
+ self.0.eq(rhs)
+ }
+}
+
+impl PartialEq<Instant> for StdInstant {
+ fn eq(&self, rhs: &Instant) -> bool {
+ self.eq(&rhs.0)
+ }
+}
+
+impl PartialOrd<StdInstant> for Instant {
+ fn partial_cmp(&self, rhs: &StdInstant) -> Option<Ordering> {
+ self.0.partial_cmp(rhs)
+ }
+}
+
+impl PartialOrd<Instant> for StdInstant {
+ fn partial_cmp(&self, rhs: &Instant) -> Option<Ordering> {
+ self.partial_cmp(&rhs.0)
+ }
+}
+
+impl AsRef<StdInstant> for Instant {
+ fn as_ref(&self) -> &StdInstant {
+ &self.0
+ }
+}
+
+impl Borrow<StdInstant> for Instant {
+ fn borrow(&self) -> &StdInstant {
+ &self.0
+ }
+}
+// endregion trait impls