diff options
Diffstat (limited to 'third_party/rust/time/src/instant.rs')
-rw-r--r-- | third_party/rust/time/src/instant.rs | 262 |
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 |