super::relative_unit!(TimeDelta);
use std::fmt;
impl TimeDelta {
const ONE_SIDED: bool = false;
pub const fn from_minutes(value: i64) -> Self {
Self::from_fraction(60_000_000, value)
}
pub fn from_minutes_float(value: f64) -> Self {
Self::from_fraction_float(60_000_000.0, value)
}
pub const fn from_seconds(value: i64) -> Self {
Self::from_fraction(1_000_000, value)
}
pub fn from_seconds_float(value: f64) -> Self {
Self::from_fraction_float(1_000_000.0, value)
}
pub const fn from_millis(value: i64) -> Self {
Self::from_fraction(1_000, value)
}
pub fn from_millis_float(value: f64) -> Self {
Self::from_fraction_float(1_000.0, value)
}
pub const fn from_micros(value: i64) -> Self {
Self::from_value(value)
}
pub fn from_micros_float(value: f64) -> Self {
Self::from_value_float(value)
}
pub const fn seconds(&self) -> i64 {
self.to_fraction(1_000_000)
}
pub fn seconds_float(&self) -> f64 {
self.to_fraction_float(1_000_000.0)
}
pub const fn ms(&self) -> i64 {
self.to_fraction(1_000)
}
pub fn ms_float(&self) -> f64 {
self.to_fraction_float(1_000.0)
}
pub const fn us(&self) -> i64 {
self.to_value()
}
pub const fn us_float(&self) -> f64 {
self.to_value_float()
}
pub const fn ns(&self) -> i64 {
self.to_multiple(1000)
}
pub fn ns_float(&self) -> f64 {
self.to_multiple_float(1000.0)
}
pub const fn seconds_or(&self, fallback_value: i64) -> i64 {
self.to_fraction_or(1_000_000, fallback_value)
}
pub const fn ms_or(&self, fallback_value: i64) -> i64 {
self.to_fraction_or(1_000, fallback_value)
}
pub const fn us_or(&self, fallback_value: i64) -> i64 {
self.to_value_or(fallback_value)
}
pub const fn abs(&self) -> Self {
if self.us() < 0 {
Self::from_micros(-self.us())
} else {
*self
}
}
}
impl fmt::Debug for TimeDelta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_plus_infinity() {
write!(f, "+inf ms")
} else if self.is_minus_infinity() {
write!(f, "-inf ms")
} else if self.us() == 0 || (self.us() % 1000) != 0 {
write!(f, "{} us", self.us())
} else if self.ms() % 1000 != 0 {
write!(f, "{} ms", self.ms())
} else {
write!(f, "{} s", self.seconds())
}
}
}
#[cfg(test)]
mod test {
use approx::assert_relative_eq;
use super::*;
#[test]
fn const_expr() {
const VALUE: i64 = -12345;
const TIME_DELTA_ZERO: TimeDelta = TimeDelta::zero();
const TIME_DELTA_PLUS_INF: TimeDelta = TimeDelta::plus_infinity();
const TIME_DELTA_MINUS_INF: TimeDelta = TimeDelta::minus_infinity();
assert!(TimeDelta::default() == TIME_DELTA_ZERO);
assert!(TIME_DELTA_ZERO.is_zero());
assert!(TIME_DELTA_PLUS_INF.is_plus_infinity());
assert!(TIME_DELTA_MINUS_INF.is_minus_infinity());
assert!(TIME_DELTA_PLUS_INF.ms_or(-1) == -1);
assert!(TIME_DELTA_PLUS_INF > TIME_DELTA_ZERO);
const TIME_DELTA_MINUTES: TimeDelta = TimeDelta::from_minutes(VALUE);
const TIME_DELTA_SECONDS: TimeDelta = TimeDelta::from_seconds(VALUE);
const TIME_DELTA_MS: TimeDelta = TimeDelta::from_millis(VALUE);
const TIME_DELTA_US: TimeDelta = TimeDelta::from_micros(VALUE);
assert!(TIME_DELTA_MINUTES.seconds_or(0) == VALUE * 60);
assert!(TIME_DELTA_SECONDS.seconds_or(0) == VALUE);
assert!(TIME_DELTA_MS.ms_or(0) == VALUE);
assert!(TIME_DELTA_US.us_or(0) == VALUE);
}
#[test]
fn get_back_same_values() {
const VALUE: i64 = 499;
for sign in [-1, 0, 1] {
let value: i64 = VALUE * sign;
assert_eq!(TimeDelta::from_millis(value).ms(), value);
assert_eq!(TimeDelta::from_micros(value).us(), value);
assert_eq!(TimeDelta::from_seconds(value).seconds(), value);
assert_eq!(TimeDelta::from_seconds(value).seconds(), value);
}
assert_eq!(TimeDelta::zero().us(), 0);
}
#[test]
fn get_different_prefix() {
const VALUE: i64 = 3000000;
assert_eq!(TimeDelta::from_micros(VALUE).seconds(), VALUE / 1000000);
assert_eq!(TimeDelta::from_millis(VALUE).seconds(), VALUE / 1000);
assert_eq!(TimeDelta::from_micros(VALUE).ms(), VALUE / 1000);
assert_eq!(TimeDelta::from_minutes(VALUE / 60).seconds(), VALUE);
assert_eq!(TimeDelta::from_millis(VALUE).us(), VALUE * 1000);
assert_eq!(TimeDelta::from_seconds(VALUE).ms(), VALUE * 1000);
assert_eq!(TimeDelta::from_seconds(VALUE).us(), VALUE * 1000000);
assert_eq!(TimeDelta::from_minutes(VALUE / 60).seconds(), VALUE);
}
#[test]
fn identity_checks() {
const VALUE: i64 = 3000;
assert!(TimeDelta::zero().is_zero());
assert!(!TimeDelta::from_millis(VALUE).is_zero());
assert!(TimeDelta::plus_infinity().is_infinite());
assert!(TimeDelta::minus_infinity().is_infinite());
assert!(!TimeDelta::zero().is_infinite());
assert!(!TimeDelta::from_millis(-VALUE).is_infinite());
assert!(!TimeDelta::from_millis(VALUE).is_infinite());
assert!(!TimeDelta::plus_infinity().is_finite());
assert!(!TimeDelta::minus_infinity().is_finite());
assert!(TimeDelta::from_millis(-VALUE).is_finite());
assert!(TimeDelta::from_millis(VALUE).is_finite());
assert!(TimeDelta::zero().is_finite());
assert!(TimeDelta::plus_infinity().is_plus_infinity());
assert!(!TimeDelta::minus_infinity().is_plus_infinity());
assert!(TimeDelta::minus_infinity().is_minus_infinity());
assert!(!TimeDelta::plus_infinity().is_minus_infinity());
}
#[test]
fn comparison_operators() {
const SMALL: i64 = 450;
const LARGE: i64 = 451;
let small: TimeDelta = TimeDelta::from_millis(SMALL);
let large: TimeDelta = TimeDelta::from_millis(LARGE);
assert_eq!(TimeDelta::zero(), TimeDelta::from_millis(0));
assert_eq!(TimeDelta::plus_infinity(), TimeDelta::plus_infinity());
assert_eq!(small, TimeDelta::from_millis(SMALL));
assert!(small <= TimeDelta::from_millis(SMALL));
assert!(small >= TimeDelta::from_millis(SMALL));
assert!(small != TimeDelta::from_millis(LARGE));
assert!(small <= TimeDelta::from_millis(LARGE));
assert!(small < TimeDelta::from_millis(LARGE));
assert!(large >= TimeDelta::from_millis(SMALL));
assert!(large > TimeDelta::from_millis(SMALL));
assert!(TimeDelta::zero() < small);
assert!(TimeDelta::zero() > TimeDelta::from_millis(-SMALL));
assert!(TimeDelta::zero() > TimeDelta::from_millis(-SMALL));
assert!(TimeDelta::plus_infinity() > large);
assert!(TimeDelta::minus_infinity() < TimeDelta::zero());
}
#[test]
fn clamping() {
const UPPER: TimeDelta = TimeDelta::from_millis(800);
const LOWER: TimeDelta = TimeDelta::from_millis(100);
const UNDER: TimeDelta = TimeDelta::from_millis(100);
const INSIDE: TimeDelta = TimeDelta::from_millis(500);
const OVER: TimeDelta = TimeDelta::from_millis(1000);
assert_eq!(UNDER.clamp(LOWER, UPPER), LOWER);
assert_eq!(INSIDE.clamp(LOWER, UPPER), INSIDE);
assert_eq!(OVER.clamp(LOWER, UPPER), UPPER);
let mut mutable_delta: TimeDelta = LOWER;
mutable_delta.clamp_mut(LOWER, UPPER);
assert_eq!(mutable_delta, LOWER);
mutable_delta = INSIDE;
mutable_delta.clamp_mut(LOWER, UPPER);
assert_eq!(mutable_delta, INSIDE);
mutable_delta = OVER;
mutable_delta.clamp_mut(LOWER, UPPER);
assert_eq!(mutable_delta, UPPER);
}
#[test]
fn can_be_inititialized_from_large_int() {
const MAX_INT: i32 = i32::MAX;
assert_eq!(
TimeDelta::from_seconds(MAX_INT as i64).us(),
MAX_INT as i64 * 1000000
);
assert_eq!(
TimeDelta::from_millis(MAX_INT as i64).us(),
MAX_INT as i64 * 1000
);
}
#[test]
fn converts_to_and_from_double() {
const MICROS: i64 = 17017;
const NANOS_DOUBLE: f64 = MICROS as f64 * 1e3;
const MICROS_DOUBLE: f64 = MICROS as f64;
const MILLIS_DOUBLE: f64 = MICROS as f64 * 1e-3;
const SECONDS_DOUBLE: f64 = MILLIS_DOUBLE * 1e-3;
assert_eq!(
TimeDelta::from_micros(MICROS).seconds_float(),
SECONDS_DOUBLE
);
assert_eq!(TimeDelta::from_seconds_float(SECONDS_DOUBLE).us(), MICROS);
assert_eq!(TimeDelta::from_micros(MICROS).ms_float(), MILLIS_DOUBLE);
assert_eq!(TimeDelta::from_millis_float(MILLIS_DOUBLE).us(), MICROS);
assert_eq!(TimeDelta::from_micros(MICROS).us_float(), MICROS_DOUBLE);
assert_eq!(TimeDelta::from_micros_float(MICROS_DOUBLE).us(), MICROS);
assert_relative_eq!(
TimeDelta::from_micros(MICROS).ns_float(),
NANOS_DOUBLE,
epsilon = 1.0
);
const PLUS_INFINITY: f64 = f64::INFINITY;
const MINUS_INFINITY: f64 = -PLUS_INFINITY;
assert_eq!(TimeDelta::plus_infinity().seconds_float(), PLUS_INFINITY);
assert_eq!(TimeDelta::minus_infinity().seconds_float(), MINUS_INFINITY);
assert_eq!(TimeDelta::plus_infinity().ms_float(), PLUS_INFINITY);
assert_eq!(TimeDelta::minus_infinity().ms_float(), MINUS_INFINITY);
assert_eq!(TimeDelta::plus_infinity().us_float(), PLUS_INFINITY);
assert_eq!(TimeDelta::minus_infinity().us_float(), MINUS_INFINITY);
assert_eq!(TimeDelta::plus_infinity().ns_float(), PLUS_INFINITY);
assert_eq!(TimeDelta::minus_infinity().ns_float(), MINUS_INFINITY);
assert!(TimeDelta::from_seconds_float(PLUS_INFINITY).is_plus_infinity());
assert!(TimeDelta::from_seconds_float(MINUS_INFINITY).is_minus_infinity());
assert!(TimeDelta::from_millis_float(PLUS_INFINITY).is_plus_infinity());
assert!(TimeDelta::from_millis_float(MINUS_INFINITY).is_minus_infinity());
assert!(TimeDelta::from_micros_float(PLUS_INFINITY).is_plus_infinity());
assert!(TimeDelta::from_micros_float(MINUS_INFINITY).is_minus_infinity());
}
#[test]
fn math_operations() {
const VALUE_A: i64 = 267;
const VALUE_B: i64 = 450;
const DELTA_A: TimeDelta = TimeDelta::from_millis(VALUE_A);
const DELTA_B: TimeDelta = TimeDelta::from_millis(VALUE_B);
assert_eq!((DELTA_A + DELTA_B).ms(), VALUE_A + VALUE_B);
assert_eq!((DELTA_A - DELTA_B).ms(), VALUE_A - VALUE_B);
assert_eq!((DELTA_B / 10).ms(), VALUE_B / 10);
assert_eq!(DELTA_B / DELTA_A, VALUE_B as f64 / VALUE_A as f64);
assert_eq!(TimeDelta::from_micros(-VALUE_A).abs().us(), VALUE_A);
assert_eq!(TimeDelta::from_micros(VALUE_A).abs().us(), VALUE_A);
let mut mutable_delta: TimeDelta = TimeDelta::from_millis(VALUE_A);
mutable_delta += TimeDelta::from_millis(VALUE_B);
assert_eq!(mutable_delta, TimeDelta::from_millis(VALUE_A + VALUE_B));
mutable_delta -= TimeDelta::from_millis(VALUE_B);
assert_eq!(mutable_delta, TimeDelta::from_millis(VALUE_A));
}
#[test]
fn multiply_by_scalar() {
const VALUE: TimeDelta = TimeDelta::from_micros(267);
const INT64: i64 = 450;
const INT32: i32 = 123;
const UNSIGNED_INT: usize = 125;
const FLOAT: f64 = 123.0;
assert_eq!((VALUE * INT64).us(), VALUE.us() * INT64);
assert_eq!(VALUE * INT64, INT64 * VALUE);
assert_eq!((VALUE * INT32).us(), VALUE.us() * INT32 as i64);
assert_eq!(VALUE * INT32, INT32 * VALUE);
assert_eq!(
(VALUE * UNSIGNED_INT).us(),
VALUE.us() * UNSIGNED_INT as i64
);
assert_eq!(VALUE * UNSIGNED_INT, UNSIGNED_INT * VALUE);
assert_relative_eq!(
(VALUE * FLOAT).us_float(),
VALUE.us_float() * FLOAT,
epsilon = 0.1
);
assert_eq!(VALUE * FLOAT, FLOAT * VALUE);
}
#[test]
fn infinity_operations() {
const VALUE: i64 = 267;
const FINITE: TimeDelta = TimeDelta::from_millis(VALUE);
assert!((TimeDelta::plus_infinity() + FINITE).is_plus_infinity());
assert!((TimeDelta::plus_infinity() - FINITE).is_plus_infinity());
assert!((FINITE + TimeDelta::plus_infinity()).is_plus_infinity());
assert!((FINITE - TimeDelta::minus_infinity()).is_plus_infinity());
assert!((TimeDelta::minus_infinity() + FINITE).is_minus_infinity());
assert!((TimeDelta::minus_infinity() - FINITE).is_minus_infinity());
assert!((FINITE + TimeDelta::minus_infinity()).is_minus_infinity());
assert!((FINITE - TimeDelta::plus_infinity()).is_minus_infinity());
}
}