use crate::{internal_prelude::*, Duration};
use core::{
cmp::{Ord, Ordering, PartialEq, PartialOrd},
ops::{Add, AddAssign, Sub, SubAssign},
time::Duration as StdDuration,
};
use std::time::Instant as StdInstant;
#[cfg_attr(docs, doc(cfg(feature = "std")))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant {
inner: StdInstant,
}
impl Instant {
#[inline(always)]
pub fn now() -> Self {
Self {
inner: StdInstant::now(),
}
}
#[inline(always)]
pub fn elapsed(self) -> Duration {
Self::now() - self
}
#[inline]
#[cfg(instant_checked_ops)]
pub fn checked_add(self, duration: Duration) -> Option<Self> {
if duration.is_zero() {
Some(self)
} else if duration.is_positive() {
self.inner.checked_add(duration.abs_std()).map(From::from)
} else {
self.inner.checked_sub(duration.abs_std()).map(From::from)
}
}
#[inline(always)]
#[cfg(instant_checked_ops)]
pub fn checked_sub(self, duration: Duration) -> Option<Self> {
self.checked_add(-duration)
}
}
#[allow(clippy::missing_docs_in_private_items)]
impl Instant {
#[inline(always)]
#[cfg(v01_deprecated_api)]
#[cfg_attr(tarpaulin, skip)]
#[deprecated(since = "0.2.0", note = "Use `rhs - lhs`")]
pub fn to(&self, later: Self) -> Duration {
later - *self
}
}
impl From<StdInstant> for Instant {
#[inline(always)]
fn from(instant: StdInstant) -> Self {
Self { inner: instant }
}
}
impl From<Instant> for StdInstant {
#[inline(always)]
fn from(instant: Instant) -> Self {
instant.inner
}
}
impl Sub for Instant {
type Output = Duration;
#[inline(always)]
fn sub(self, other: Self) -> Self::Output {
match self.inner.cmp(&other.inner) {
Ordering::Equal => Duration::zero(),
Ordering::Greater => (self.inner - other.inner)
.try_into()
.expect("overflow converting `std::time::Duration` to `time::Duration`"),
Ordering::Less => -Duration::try_from(other.inner - self.inner)
.expect("overflow converting `std::time::Duration` to `time::Duration`"),
}
}
}
impl Sub<StdInstant> for Instant {
type Output = Duration;
#[inline(always)]
fn sub(self, other: StdInstant) -> Self::Output {
self - Self::from(other)
}
}
impl Sub<Instant> for StdInstant {
type Output = Duration;
#[inline(always)]
fn sub(self, other: Instant) -> Self::Output {
Instant::from(self) - other
}
}
impl Add<Duration> for Instant {
type Output = Self;
#[inline(always)]
fn add(self, duration: Duration) -> Self::Output {
if duration.is_positive() {
(self.inner + duration.abs_std()).into()
} else if duration.is_negative() {
(self.inner - duration.abs_std()).into()
} else {
self
}
}
}
impl Add<Duration> for StdInstant {
type Output = Self;
#[inline(always)]
fn add(self, duration: Duration) -> Self::Output {
(Instant::from(self) + duration).into()
}
}
impl Add<StdDuration> for Instant {
type Output = Self;
#[inline(always)]
fn add(self, duration: StdDuration) -> Self::Output {
Self {
inner: self.inner + duration,
}
}
}
impl AddAssign<Duration> for Instant {
#[inline(always)]
fn add_assign(&mut self, duration: Duration) {
*self = *self + duration;
}
}
impl AddAssign<Duration> for StdInstant {
#[inline(always)]
fn add_assign(&mut self, duration: Duration) {
*self = *self + duration;
}
}
impl AddAssign<StdDuration> for Instant {
#[inline(always)]
fn add_assign(&mut self, duration: StdDuration) {
*self = *self + duration;
}
}
impl Sub<Duration> for Instant {
type Output = Self;
#[inline(always)]
fn sub(self, duration: Duration) -> Self::Output {
self + -duration
}
}
impl Sub<Duration> for StdInstant {
type Output = Self;
#[inline(always)]
fn sub(self, duration: Duration) -> Self::Output {
(Instant::from(self) - duration).into()
}
}
impl Sub<StdDuration> for Instant {
type Output = Self;
#[inline(always)]
fn sub(self, duration: StdDuration) -> Self::Output {
Self {
inner: self.inner - duration,
}
}
}
impl SubAssign<Duration> for Instant {
#[inline(always)]
fn sub_assign(&mut self, duration: Duration) {
*self = *self - duration;
}
}
impl SubAssign<Duration> for StdInstant {
#[inline(always)]
fn sub_assign(&mut self, duration: Duration) {
*self = *self - duration;
}
}
impl SubAssign<StdDuration> for Instant {
#[inline(always)]
fn sub_assign(&mut self, duration: StdDuration) {
*self = *self - duration;
}
}
impl PartialEq<StdInstant> for Instant {
#[inline(always)]
fn eq(&self, rhs: &StdInstant) -> bool {
self.inner.eq(rhs)
}
}
impl PartialEq<Instant> for StdInstant {
#[inline(always)]
fn eq(&self, rhs: &Instant) -> bool {
self.eq(&rhs.inner)
}
}
impl PartialOrd<StdInstant> for Instant {
#[inline(always)]
fn partial_cmp(&self, rhs: &StdInstant) -> Option<Ordering> {
self.inner.partial_cmp(rhs)
}
}
impl PartialOrd<Instant> for StdInstant {
#[inline(always)]
fn partial_cmp(&self, rhs: &Instant) -> Option<Ordering> {
self.partial_cmp(&rhs.inner)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::prelude::*;
use std::thread;
#[test]
fn elapsed() {
let instant = Instant::now();
thread::sleep(100.std_milliseconds());
assert!(instant.elapsed() >= 100.milliseconds());
}
#[test]
#[cfg(instant_checked_ops)]
fn checked_add() {
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()));
}
#[test]
#[cfg(instant_checked_ops)]
fn checked_sub() {
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()));
}
#[test]
fn from_std() {
let now_time = Instant::now();
let now_std = StdInstant::from(now_time);
assert_eq!(now_time, now_std);
}
#[test]
fn to_std() {
let now_std = StdInstant::now();
let now_time = Instant::from(now_std);
assert_eq!(now_time, now_std);
}
#[test]
fn sub() {
let start = Instant::now();
thread::sleep(100.std_milliseconds());
assert!(Instant::now() - start >= 100.milliseconds());
}
#[test]
fn sub_std() {
let start = StdInstant::now();
thread::sleep(100.std_milliseconds());
assert!(Instant::now() - start >= 100.milliseconds());
}
#[test]
fn std_sub() {
let start = Instant::now();
thread::sleep(100.std_milliseconds());
assert!(StdInstant::now() - start >= 100.milliseconds());
}
#[test]
fn add_duration() {
let start = Instant::now();
thread::sleep(100.std_milliseconds());
assert!(start + 100.milliseconds() <= Instant::now());
}
#[test]
fn std_add_duration() {
let start = StdInstant::now();
thread::sleep(100.std_milliseconds());
assert!(start + 100.milliseconds() <= StdInstant::now());
}
#[test]
fn add_std_duration() {
let start = Instant::now();
thread::sleep(100.std_milliseconds());
assert!(start + 100.std_milliseconds() <= Instant::now());
}
#[test]
fn add_assign_duration() {
let mut start = Instant::now();
thread::sleep(100.std_milliseconds());
start += 100.milliseconds();
assert!(start <= Instant::now());
}
#[test]
fn std_add_assign_duration() {
let mut start = StdInstant::now();
thread::sleep(100.std_milliseconds());
start += 100.milliseconds();
assert!(start <= StdInstant::now());
}
#[test]
fn add_assign_std_duration() {
let mut start = Instant::now();
thread::sleep(100.std_milliseconds());
start += 100.std_milliseconds();
assert!(start <= Instant::now());
}
#[test]
fn sub_duration() {
let instant = Instant::now();
assert!(instant - 100.milliseconds() <= Instant::now());
}
#[test]
fn std_sub_duration() {
let instant = StdInstant::now();
assert!(instant - 100.milliseconds() <= StdInstant::now());
}
#[test]
fn sub_std_duration() {
let instant = Instant::now();
assert!(instant - 100.std_milliseconds() <= Instant::now());
}
#[test]
fn sub_assign_duration() {
let mut instant = Instant::now();
instant -= 100.milliseconds();
assert!(instant <= Instant::now());
}
#[test]
fn std_sub_assign_duration() {
let mut instant = StdInstant::now();
instant -= 100.milliseconds();
assert!(instant <= StdInstant::now());
}
#[test]
fn sub_assign_std_duration() {
let mut instant = Instant::now();
instant -= 100.std_milliseconds();
assert!(instant <= Instant::now());
}
#[test]
fn eq_std() {
let now_time = Instant::now();
let now_std = StdInstant::from(now_time);
assert_eq!(now_time, now_std);
}
#[test]
fn std_eq() {
let now_time = Instant::now();
let now_std = StdInstant::from(now_time);
assert_eq!(now_std, now_time);
}
#[test]
fn ord_std() {
let now_time = Instant::now();
let now_std = StdInstant::from(now_time) + 1.seconds();
assert!(now_time < now_std);
let now_time = Instant::now();
let now_std = StdInstant::from(now_time) - 1.seconds();
assert!(now_time > now_std);
}
#[test]
fn std_ord() {
let now_time = Instant::now();
let now_std = StdInstant::from(now_time) + 1.seconds();
assert!(now_std > now_time);
let now_time = Instant::now();
let now_std = StdInstant::from(now_time) - 1.seconds();
assert!(now_std < now_time);
}
#[test]
fn sub_regression() {
let now = Instant::now();
let future = now + Duration::seconds(5);
let past = now - Duration::seconds(5);
assert_eq!(future - now, Duration::seconds(5));
assert_eq!(now - past, Duration::seconds(5));
assert_eq!(future - past, Duration::seconds(10));
assert_eq!(now - future, Duration::seconds(-5));
assert_eq!(past - now, Duration::seconds(-5));
assert_eq!(past - future, Duration::seconds(-10));
}
}