mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-01-08 14:22:58 +00:00
feat: Implement TimestampMillis and RangeMillis (#56)
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -639,6 +639,10 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "common-time"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "console-api"
|
||||
version = "0.2.0"
|
||||
|
||||
@@ -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",
|
||||
|
||||
8
src/common/time/Cargo.toml
Normal file
8
src/common/time/Cargo.toml
Normal 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]
|
||||
5
src/common/time/src/lib.rs
Normal file
5
src/common/time/src/lib.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
pub mod range;
|
||||
pub mod timestamp;
|
||||
|
||||
pub use range::RangeMillis;
|
||||
pub use timestamp::TimestampMillis;
|
||||
95
src/common/time/src/range.rs
Normal file
95
src/common/time/src/range.rs
Normal 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));
|
||||
}
|
||||
}
|
||||
73
src/common/time/src/timestamp.rs
Normal file
73
src/common/time/src/timestamp.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user