time/ext/instant.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
use std::time::Instant as StdInstant;
use crate::Duration;
/// Sealed trait to prevent downstream implementations.
mod sealed {
/// A trait that cannot be implemented by downstream users.
pub trait Sealed: Sized {}
impl Sealed for std::time::Instant {}
}
/// An extension trait for [`std::time::Instant`] that adds methods for
/// [`time::Duration`](Duration)s.
pub trait InstantExt: sealed::Sealed {
/// # Panics
///
/// This function may panic if the resulting point in time cannot be represented by the
/// underlying data structure. See [`InstantExt::checked_add_signed`] for a non-panicking
/// version.
fn add_signed(self, duration: Duration) -> Self {
self.checked_add_signed(duration)
.expect("overflow when adding duration to instant")
}
/// # Panics
///
/// This function may panic if the resulting point in time cannot be represented by the
/// underlying data structure. See [`InstantExt::checked_sub_signed`] for a non-panicking
/// version.
fn sub_signed(self, duration: Duration) -> Self {
self.checked_sub_signed(duration)
.expect("overflow when subtracting duration from instant")
}
/// Returns `Some(t)` where `t` is the time `self.checked_add_signed(duration)` if `t` can be
/// represented as `Instant` (which means it's inside the bounds of the underlying data
/// structure), `None` otherwise.
fn checked_add_signed(&self, duration: Duration) -> Option<Self>;
/// Returns `Some(t)` where `t` is the time `self.checked_sub_signed(duration)` if `t` can be
/// represented as `Instant` (which means it's inside the bounds of the underlying data
/// structure), `None` otherwise.
fn checked_sub_signed(&self, duration: Duration) -> Option<Self>;
/// Returns the amount of time elapsed from another instant to this one. This will be negative
/// if `earlier` is later than `self`.
///
/// # Example
///
/// ```rust
/// # use std::thread::sleep;
/// # use std::time::{Duration, Instant};
/// # use time::ext::InstantExt;
/// let now = Instant::now();
/// sleep(Duration::new(1, 0));
/// let new_now = Instant::now();
/// println!("{:?}", new_now.signed_duration_since(now)); // positive
/// println!("{:?}", now.signed_duration_since(new_now)); // negative
/// ```
fn signed_duration_since(&self, earlier: Self) -> Duration;
}
impl InstantExt for StdInstant {
fn checked_add_signed(&self, duration: Duration) -> Option<Self> {
if duration.is_positive() {
self.checked_add(duration.unsigned_abs())
} else if duration.is_negative() {
self.checked_sub(duration.unsigned_abs())
} else {
debug_assert!(duration.is_zero());
Some(*self)
}
}
fn checked_sub_signed(&self, duration: Duration) -> Option<Self> {
if duration.is_positive() {
self.checked_sub(duration.unsigned_abs())
} else if duration.is_negative() {
self.checked_add(duration.unsigned_abs())
} else {
debug_assert!(duration.is_zero());
Some(*self)
}
}
fn signed_duration_since(&self, earlier: Self) -> Duration {
if *self > earlier {
self.saturating_duration_since(earlier)
.try_into()
.unwrap_or(Duration::MAX)
} else {
earlier
.saturating_duration_since(*self)
.try_into()
.map_or(Duration::MIN, |d: Duration| -d)
}
}
}