pub trait Clock {
fn stamp(&self) -> u64;
}
#[inline]
pub fn elapsed(from: u64, to: u64) -> u64 {
to.saturating_sub(from)
}
pub struct EpochClock {
now: u64,
}
impl EpochClock {
pub fn new(initial: u64) -> Self {
Self { now: initial }
}
#[inline]
pub fn set(&mut self, stamp: u64) {
self.now = stamp;
}
#[inline]
pub fn advance(&mut self, delta: u64) {
self.now = self.now.saturating_add(delta);
}
}
impl Clock for EpochClock {
#[inline]
fn stamp(&self) -> u64 {
self.now
}
}
#[cfg(feature = "std")]
mod wall {
use std::time::Instant;
pub struct WallClock {
epoch: Instant,
}
impl WallClock {
pub fn new() -> Self {
Self {
epoch: Instant::now(),
}
}
pub fn with_epoch(epoch: Instant) -> Self {
Self { epoch }
}
}
impl Default for WallClock {
fn default() -> Self {
Self::new()
}
}
impl super::Clock for WallClock {
#[inline]
fn stamp(&self) -> u64 {
self.epoch.elapsed().as_nanos() as u64
}
}
}
#[cfg(feature = "std")]
pub use wall::WallClock;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn epoch_clock_basic() {
let mut c = EpochClock::new(0);
assert_eq!(c.stamp(), 0);
c.set(100);
assert_eq!(c.stamp(), 100);
}
#[test]
fn epoch_clock_advance() {
let mut c = EpochClock::new(10);
c.advance(5);
assert_eq!(c.stamp(), 15);
}
#[test]
fn epoch_clock_advance_saturates() {
let mut c = EpochClock::new(u64::MAX - 1);
c.advance(10);
assert_eq!(c.stamp(), u64::MAX);
}
#[test]
fn elapsed_basic() {
assert_eq!(elapsed(10, 20), 10);
assert_eq!(elapsed(20, 10), 0);
}
#[cfg(feature = "std")]
#[test]
fn wall_clock_monotonic() {
let c = WallClock::new();
let t0 = c.stamp();
let t1 = c.stamp();
assert!(t1 >= t0);
}
#[cfg(feature = "std")]
#[test]
fn wall_clock_default() {
let c = WallClock::default();
let _ = c.stamp();
}
}