feat: Implement TimestampMillis and RangeMillis (#56)

This commit is contained in:
evenyag
2022-06-29 20:55:27 +08:00
committed by GitHub
parent 651bdbaa71
commit 11bf970efd
6 changed files with 186 additions and 0 deletions

4
Cargo.lock generated
View File

@@ -639,6 +639,10 @@ dependencies = [
"tracing-subscriber",
]
[[package]]
name = "common-time"
version = "0.1.0"
[[package]]
name = "console-api"
version = "0.2.0"

View File

@@ -5,6 +5,7 @@ members = [
"src/common/function",
"src/common/runtime",
"src/common/telemetry",
"src/common/time",
"src/common/query",
"src/common/recordbatch",
"src/cmd",

View File

@@ -0,0 +1,8 @@
[package]
name = "common-time"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@@ -0,0 +1,5 @@
pub mod range;
pub mod timestamp;
pub use range::RangeMillis;
pub use timestamp::TimestampMillis;

View File

@@ -0,0 +1,95 @@
use crate::timestamp::TimestampMillis;
/// A half-open time range.
///
/// The time range contains all timestamp `ts` that `ts >= start` and `ts < end`. It is
/// empty if `start == end`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TimeRange<T> {
start: T,
end: T,
}
impl<T> TimeRange<T> {
/// Create a new range that contains timestamp in `[start, end)`.
///
/// Returns `None` if `start` > `end`.
pub fn new<U: PartialOrd + Into<T>>(start: U, end: U) -> Option<TimeRange<T>> {
if start <= end {
let (start, end) = (start.into(), end.into());
Some(TimeRange { start, end })
} else {
None
}
}
/// Returns the lower bound of the range (inclusive).
#[inline]
pub fn start(&self) -> &T {
&self.start
}
/// Returns the upper bound of the range (exclusive).
#[inline]
pub fn end(&self) -> &T {
&self.end
}
/// Returns true if `timestamp` is contained in the range.
pub fn contains<U: PartialOrd<T>>(&self, timestamp: &U) -> bool {
*timestamp >= self.start && *timestamp < self.end
}
}
impl<T: PartialOrd> TimeRange<T> {
/// Returns true if the range contains no timestamps.
#[inline]
pub fn is_empty(&self) -> bool {
self.start >= self.end
}
}
/// Time range in milliseconds.
pub type RangeMillis = TimeRange<TimestampMillis>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_range() {
let (start, end) = (TimestampMillis::new(0), TimestampMillis::new(100));
let range = RangeMillis::new(start, end).unwrap();
assert_eq!(start, *range.start());
assert_eq!(end, *range.end());
let range2 = RangeMillis::new(0, 100).unwrap();
assert_eq!(range, range2);
let range_eq = RangeMillis::new(123, 123).unwrap();
assert_eq!(range_eq.start(), range_eq.end());
assert_eq!(None, RangeMillis::new(1, 0));
}
#[test]
fn test_range_contains() {
let range = RangeMillis::new(-10, 10).unwrap();
assert!(!range.is_empty());
assert!(range.contains(&-10));
assert!(range.contains(&0));
assert!(range.contains(&9));
assert!(!range.contains(&10));
let range = RangeMillis::new(i64::MIN, i64::MAX).unwrap();
assert!(!range.is_empty());
assert!(range.contains(&TimestampMillis::MIN));
assert!(range.contains(&TimestampMillis::MAX));
assert!(!range.contains(&TimestampMillis::INF));
let range = RangeMillis::new(0, 0).unwrap();
assert!(range.is_empty());
assert!(!range.contains(&0));
}
}

View File

@@ -0,0 +1,73 @@
use std::cmp::Ordering;
/// Unix timestamp in millisecond resolution.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TimestampMillis(i64);
impl TimestampMillis {
/// Positive infinity.
pub const INF: TimestampMillis = TimestampMillis::new(i64::MAX);
/// Maximum value of a timestamp.
///
/// The maximum value of i64 is reserved for infinity.
pub const MAX: TimestampMillis = TimestampMillis::new(i64::MAX - 1);
/// Minimum value of a timestamp.
pub const MIN: TimestampMillis = TimestampMillis::new(i64::MIN);
/// Create a new timestamp from unix timestamp in milliseconds.
pub const fn new(ms: i64) -> TimestampMillis {
TimestampMillis(ms)
}
}
impl From<i64> for TimestampMillis {
fn from(ms: i64) -> TimestampMillis {
TimestampMillis::new(ms)
}
}
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))
}
}
#[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_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);
}
}