super::unit_base!(Timestamp);
use std::fmt;
use std::ops::*;
use super::TimeDelta;
impl Timestamp {
const ONE_SIDED: bool = false;
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 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)
}
}
impl Add<TimeDelta> for Timestamp {
type Output = Self;
fn add(self, delta: TimeDelta) -> Self {
if self.is_plus_infinity() || delta.is_plus_infinity() {
assert!(!self.is_minus_infinity());
assert!(!delta.is_minus_infinity());
return Self::plus_infinity();
} else if self.is_minus_infinity() || delta.is_minus_infinity() {
assert!(!self.is_plus_infinity());
assert!(!delta.is_plus_infinity());
return Self::minus_infinity();
}
Timestamp::from_micros(self.us() + delta.us())
}
}
impl Sub<TimeDelta> for Timestamp {
type Output = Self;
fn sub(self, delta: TimeDelta) -> Self {
if self.is_plus_infinity() || delta.is_minus_infinity() {
assert!(!self.is_minus_infinity());
assert!(!delta.is_plus_infinity());
return Self::plus_infinity();
} else if self.is_minus_infinity() || delta.is_plus_infinity() {
assert!(!self.is_plus_infinity());
assert!(!delta.is_minus_infinity());
return Self::minus_infinity();
}
Timestamp::from_micros(self.us() - delta.us())
}
}
impl Sub for Timestamp {
type Output = TimeDelta;
fn sub(self, other: Self) -> TimeDelta {
if self.is_plus_infinity() || other.is_minus_infinity() {
assert!(!self.is_minus_infinity());
assert!(!other.is_plus_infinity());
return TimeDelta::plus_infinity();
} else if self.is_minus_infinity() || other.is_plus_infinity() {
assert!(!self.is_plus_infinity());
assert!(!other.is_minus_infinity());
return TimeDelta::minus_infinity();
}
TimeDelta::from_micros(self.us() - other.us())
}
}
impl AddAssign<TimeDelta> for Timestamp {
fn add_assign(&mut self, delta: TimeDelta) {
*self = *self + delta;
}
}
impl SubAssign<TimeDelta> for Timestamp {
fn sub_assign(&mut self, delta: TimeDelta) {
*self = *self - delta;
}
}
impl fmt::Debug for Timestamp {
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 super::*;
#[test]
fn const_expr() {
const VALUE: i64 = 12345;
const TIMESTAMP_INF: Timestamp = Timestamp::plus_infinity();
assert!(TIMESTAMP_INF.is_infinite());
assert!(TIMESTAMP_INF.ms_or(-1) == -1);
const TIMESTAMP_SECONDS: Timestamp = Timestamp::from_seconds(VALUE);
const TIMESTAMP_MS: Timestamp = Timestamp::from_millis(VALUE);
const TIMESTAMP_US: Timestamp = Timestamp::from_micros(VALUE);
assert!(TIMESTAMP_SECONDS.seconds_or(0) == VALUE);
assert!(TIMESTAMP_MS.ms_or(0) == VALUE);
assert!(TIMESTAMP_US.us_or(0) == VALUE);
assert!(TIMESTAMP_MS > TIMESTAMP_US);
assert_eq!(TIMESTAMP_SECONDS.seconds(), VALUE);
assert_eq!(TIMESTAMP_MS.ms(), VALUE);
assert_eq!(TIMESTAMP_US.us(), VALUE);
}
#[test]
fn get_back_same_values() {
const VALUE: i64 = 499;
assert_eq!(Timestamp::from_millis(VALUE).ms(), VALUE);
assert_eq!(Timestamp::from_micros(VALUE).us(), VALUE);
assert_eq!(Timestamp::from_seconds(VALUE).seconds(), VALUE);
}
#[test]
fn get_different_prefix() {
const VALUE: i64 = 3000000;
assert_eq!(Timestamp::from_micros(VALUE).seconds(), VALUE / 1000000);
assert_eq!(Timestamp::from_millis(VALUE).seconds(), VALUE / 1000);
assert_eq!(Timestamp::from_micros(VALUE).ms(), VALUE / 1000);
assert_eq!(Timestamp::from_millis(VALUE).us(), VALUE * 1000);
assert_eq!(Timestamp::from_seconds(VALUE).ms(), VALUE * 1000);
assert_eq!(Timestamp::from_seconds(VALUE).us(), VALUE * 1000000);
}
#[test]
fn identity_checks() {
const VALUE: i64 = 3000;
assert!(Timestamp::plus_infinity().is_infinite());
assert!(Timestamp::minus_infinity().is_infinite());
assert!(!Timestamp::from_millis(VALUE).is_infinite());
assert!(!Timestamp::plus_infinity().is_finite());
assert!(!Timestamp::minus_infinity().is_finite());
assert!(Timestamp::from_millis(VALUE).is_finite());
assert!(Timestamp::plus_infinity().is_plus_infinity());
assert!(!Timestamp::minus_infinity().is_plus_infinity());
assert!(Timestamp::minus_infinity().is_minus_infinity());
assert!(!Timestamp::plus_infinity().is_minus_infinity());
}
#[test]
fn comparison_operators() {
const SMALL: i64 = 450;
const LARGE: i64 = 451;
assert_eq!(Timestamp::plus_infinity(), Timestamp::plus_infinity());
assert!(Timestamp::plus_infinity() >= Timestamp::plus_infinity());
assert!(Timestamp::plus_infinity() > Timestamp::from_millis(LARGE));
assert_eq!(Timestamp::from_millis(SMALL), Timestamp::from_millis(SMALL));
assert!(Timestamp::from_millis(SMALL) <= Timestamp::from_millis(SMALL));
assert!(Timestamp::from_millis(SMALL) >= Timestamp::from_millis(SMALL));
assert!(Timestamp::from_millis(SMALL) != Timestamp::from_millis(LARGE));
assert!(Timestamp::from_millis(SMALL) <= Timestamp::from_millis(LARGE));
assert!(Timestamp::from_millis(SMALL) < Timestamp::from_millis(LARGE));
assert!(Timestamp::from_millis(LARGE) >= Timestamp::from_millis(SMALL));
assert!(Timestamp::from_millis(LARGE) > Timestamp::from_millis(SMALL));
}
#[test]
fn can_be_inititialized_from_large_int() {
const MAX_INT: i32 = i32::MAX;
assert_eq!(
Timestamp::from_seconds(MAX_INT as _).us(),
MAX_INT as i64 * 1000000
);
assert_eq!(
Timestamp::from_millis(MAX_INT as _).us(),
MAX_INT as i64 * 1000
);
}
#[test]
fn converts_to_and_from_double() {
const MICROS: i64 = 17017;
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!(
Timestamp::from_micros(MICROS).seconds_float(),
SECONDS_DOUBLE
);
assert_eq!(Timestamp::from_seconds_float(SECONDS_DOUBLE).us(), MICROS);
assert_eq!(Timestamp::from_micros(MICROS).ms_float(), MILLIS_DOUBLE);
assert_eq!(Timestamp::from_millis_float(MILLIS_DOUBLE).us(), MICROS);
assert_eq!(Timestamp::from_micros(MICROS).us_float(), MICROS_DOUBLE);
assert_eq!(Timestamp::from_micros_float(MICROS_DOUBLE).us(), MICROS);
const PLUS_INFINITY: f64 = f64::INFINITY;
const MINUS_INFINITY: f64 = -PLUS_INFINITY;
assert_eq!(Timestamp::plus_infinity().seconds_float(), PLUS_INFINITY);
assert_eq!(Timestamp::minus_infinity().seconds_float(), MINUS_INFINITY);
assert_eq!(Timestamp::plus_infinity().ms_float(), PLUS_INFINITY);
assert_eq!(Timestamp::minus_infinity().ms_float(), MINUS_INFINITY);
assert_eq!(Timestamp::plus_infinity().us_float(), PLUS_INFINITY);
assert_eq!(Timestamp::minus_infinity().us_float(), MINUS_INFINITY);
assert!(Timestamp::from_seconds_float(PLUS_INFINITY).is_plus_infinity());
assert!(Timestamp::from_seconds_float(MINUS_INFINITY).is_minus_infinity());
assert!(Timestamp::from_millis_float(PLUS_INFINITY).is_plus_infinity());
assert!(Timestamp::from_millis_float(MINUS_INFINITY).is_minus_infinity());
assert!(Timestamp::from_micros_float(PLUS_INFINITY).is_plus_infinity());
assert!(Timestamp::from_micros_float(MINUS_INFINITY).is_minus_infinity());
}
#[test]
fn timestamp_and_time_delta_math() {
const VALUE_A: i64 = 267;
const VALUE_B: i64 = 450;
const TIME_A: Timestamp = Timestamp::from_millis(VALUE_A);
const TIME_B: Timestamp = Timestamp::from_millis(VALUE_B);
const DELTA_A: TimeDelta = TimeDelta::from_millis(VALUE_A);
const DELTA_B: TimeDelta = TimeDelta::from_millis(VALUE_B);
assert_eq!((TIME_A - TIME_B), TimeDelta::from_millis(VALUE_A - VALUE_B));
assert_eq!(
(TIME_B - DELTA_A),
Timestamp::from_millis(VALUE_B - VALUE_A)
);
assert_eq!(
(TIME_B + DELTA_A),
Timestamp::from_millis(VALUE_B + VALUE_A)
);
let mut mutable_time: Timestamp = TIME_A;
mutable_time += DELTA_B;
assert_eq!(mutable_time, TIME_A + DELTA_B);
mutable_time -= DELTA_B;
assert_eq!(mutable_time, TIME_A);
}
#[test]
fn infinity_operations() {
const VALUE: i64 = 267;
const FINITE_TIME: Timestamp = Timestamp::from_millis(VALUE);
const FINITE_DELTA: TimeDelta = TimeDelta::from_millis(VALUE);
assert!((Timestamp::plus_infinity() + FINITE_DELTA).is_infinite());
assert!((Timestamp::plus_infinity() - FINITE_DELTA).is_infinite());
assert!((FINITE_TIME + TimeDelta::plus_infinity()).is_infinite());
assert!((FINITE_TIME - TimeDelta::minus_infinity()).is_infinite());
}
}