#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct Timestamp {
data: u64,
}
impl Timestamp {
pub fn from_parts(millis: u64, counter: u16) -> Self {
assert!(
millis >> (u64::BITS - COUNTER_BITS) == 0,
"millis {millis} exceeds the 48-bit wall field"
);
Self {
data: (millis << COUNTER_BITS) | counter as u64,
}
}
pub fn from_raw(data: u64) -> Self {
Self { data }
}
pub fn raw(&self) -> u64 {
self.data
}
pub fn millis(&self) -> u64 {
self.data >> COUNTER_BITS
}
pub fn counter(&self) -> u16 {
(self.data & COUNTER_MASK) as u16
}
}
impl From<u64> for Timestamp {
fn from(data: u64) -> Self {
Self { data }
}
}
impl From<Timestamp> for u64 {
fn from(ts: Timestamp) -> u64 {
ts.data
}
}
const COUNTER_BITS: u32 = 16;
const COUNTER_MASK: u64 = (1 << COUNTER_BITS) - 1;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn timestamp_parts_roundtrip() {
let t = Timestamp::from_parts(1_700_000_000_000, 42);
assert_eq!(t.millis(), 1_700_000_000_000);
assert_eq!(t.counter(), 42);
assert_eq!(t.raw(), (1_700_000_000_000u64 << 16) | 42);
}
#[test]
fn timestamp_ordering_matches_raw_u64() {
let earlier = Timestamp::from_parts(100, 5);
let later_counter = Timestamp::from_parts(100, 6);
assert!(later_counter > earlier);
let next_ms = Timestamp::from_parts(101, 0);
let max_counter_prev = Timestamp::from_parts(100, u16::MAX);
assert!(next_ms > max_counter_prev);
}
#[test]
#[should_panic = "exceeds the 48-bit wall field"]
fn from_parts_rejects_wall_past_ceiling() {
let _ = Timestamp::from_parts(1 << (u64::BITS - COUNTER_BITS), 0);
}
}