common_time/
timestamp_millis.rsuse std::cmp::Ordering;
use crate::util::div_ceil;
use crate::Timestamp;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct TimestampMillis(i64);
impl TimestampMillis {
pub const INF: TimestampMillis = TimestampMillis::new(i64::MAX);
pub const MAX: TimestampMillis = TimestampMillis::new(i64::MAX - 1);
pub const MIN: TimestampMillis = TimestampMillis::new(i64::MIN);
pub const fn new(ms: i64) -> TimestampMillis {
TimestampMillis(ms)
}
pub fn as_i64(&self) -> i64 {
self.0
}
}
impl From<i64> for TimestampMillis {
fn from(ms: i64) -> TimestampMillis {
TimestampMillis::new(ms)
}
}
impl From<TimestampMillis> for i64 {
fn from(ts: TimestampMillis) -> Self {
ts.0
}
}
impl PartialEq<i64> for TimestampMillis {
fn eq(&self, other: &i64) -> bool {
self.0 == *other
}
}
impl PartialEq<TimestampMillis> for i64 {
fn eq(&self, other: &TimestampMillis) -> bool {
*self == other.0
}
}
impl PartialOrd<i64> for TimestampMillis {
fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
Some(self.0.cmp(other))
}
}
impl PartialOrd<TimestampMillis> for i64 {
fn partial_cmp(&self, other: &TimestampMillis) -> Option<Ordering> {
Some(self.cmp(&other.0))
}
}
pub trait BucketAligned: Sized {
fn align_by_bucket(self, bucket_duration: i64) -> Option<Self>;
fn align_to_ceil_by_bucket(self, bucket_duration: i64) -> Option<Self>;
}
impl BucketAligned for i64 {
fn align_by_bucket(self, bucket_duration: i64) -> Option<Self> {
assert!(bucket_duration > 0, "{}", bucket_duration);
self.checked_div_euclid(bucket_duration)
.and_then(|val| val.checked_mul(bucket_duration))
}
fn align_to_ceil_by_bucket(self, bucket_duration: i64) -> Option<Self> {
assert!(bucket_duration > 0, "{}", bucket_duration);
div_ceil(self, bucket_duration).checked_mul(bucket_duration)
}
}
impl BucketAligned for Timestamp {
fn align_by_bucket(self, bucket_duration: i64) -> Option<Self> {
assert!(bucket_duration > 0, "{}", bucket_duration);
let unit = self.unit();
self.value()
.align_by_bucket(bucket_duration)
.map(|val| Timestamp::new(val, unit))
}
fn align_to_ceil_by_bucket(self, bucket_duration: i64) -> Option<Self> {
assert!(bucket_duration > 0, "{}", bucket_duration);
let unit = self.unit();
self.value()
.align_to_ceil_by_bucket(bucket_duration)
.map(|val| Timestamp::new(val, unit))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_timestamp() {
let ts = 123456;
let timestamp = TimestampMillis::from(ts);
assert_eq!(timestamp, ts);
assert_eq!(ts, timestamp);
assert_eq!(ts, timestamp.as_i64());
assert_ne!(TimestampMillis::new(0), timestamp);
assert!(TimestampMillis::new(-123) < TimestampMillis::new(0));
assert!(TimestampMillis::new(10) < 20);
assert!(10 < TimestampMillis::new(20));
assert_eq!(i64::MAX, TimestampMillis::INF);
assert_eq!(i64::MAX - 1, TimestampMillis::MAX);
assert_eq!(i64::MIN, TimestampMillis::MIN);
}
#[test]
fn test_align_by_bucket() {
let bucket = 100;
assert_eq!(
Timestamp::new_millisecond(0),
Timestamp::new_millisecond(0)
.align_by_bucket(bucket)
.unwrap()
);
assert_eq!(
Timestamp::new_millisecond(0),
Timestamp::new_millisecond(1)
.align_by_bucket(bucket)
.unwrap()
);
assert_eq!(
Timestamp::new_millisecond(0),
Timestamp::new_millisecond(99)
.align_by_bucket(bucket)
.unwrap()
);
assert_eq!(
Timestamp::new_millisecond(100),
Timestamp::new_millisecond(100)
.align_by_bucket(bucket)
.unwrap()
);
assert_eq!(
Timestamp::new_millisecond(100),
Timestamp::new_millisecond(199)
.align_by_bucket(bucket)
.unwrap()
);
assert_eq!(
Timestamp::new_millisecond(0),
Timestamp::new_millisecond(i64::MAX - 1)
.align_by_bucket(i64::MAX)
.unwrap()
);
assert_eq!(
Timestamp::new_millisecond(i64::MAX),
Timestamp::new_millisecond(i64::MAX)
.align_by_bucket(i64::MAX)
.unwrap()
);
assert_eq!(
None,
Timestamp::new_millisecond(i64::MIN).align_by_bucket(bucket)
);
}
#[test]
fn test_align_to_ceil() {
assert_eq!(None, i64::MAX.align_to_ceil_by_bucket(10));
assert_eq!(
Some(i64::MAX - (i64::MAX % 10)),
(i64::MAX - (i64::MAX % 10)).align_to_ceil_by_bucket(10)
);
assert_eq!(Some(i64::MAX), i64::MAX.align_to_ceil_by_bucket(1));
assert_eq!(Some(i64::MAX), i64::MAX.align_to_ceil_by_bucket(1));
assert_eq!(Some(i64::MAX), i64::MAX.align_to_ceil_by_bucket(i64::MAX));
assert_eq!(
Some(i64::MIN - (i64::MIN % 10)),
i64::MIN.align_to_ceil_by_bucket(10)
);
assert_eq!(Some(i64::MIN), i64::MIN.align_to_ceil_by_bucket(1));
assert_eq!(Some(3), 1i64.align_to_ceil_by_bucket(3));
assert_eq!(Some(3), 3i64.align_to_ceil_by_bucket(3));
assert_eq!(Some(6), 4i64.align_to_ceil_by_bucket(3));
assert_eq!(Some(0), 0i64.align_to_ceil_by_bucket(3));
assert_eq!(Some(0), (-1i64).align_to_ceil_by_bucket(3));
assert_eq!(Some(0), (-2i64).align_to_ceil_by_bucket(3));
assert_eq!(Some(-3), (-3i64).align_to_ceil_by_bucket(3));
assert_eq!(Some(-3), (-4i64).align_to_ceil_by_bucket(3));
}
}