use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering::Relaxed};
use std::time::{Duration, Instant};
pub trait Clock: Clone + Send + Sync + 'static {
fn now(&self) -> Duration;
}
#[derive(Clone, Copy, Debug)]
pub struct SystemClock {
origin: Instant,
}
impl SystemClock {
pub fn new() -> Self {
Self { origin: Instant::now() }
}
}
impl Default for SystemClock {
fn default() -> Self {
Self::new()
}
}
impl Clock for SystemClock {
#[inline]
fn now(&self) -> Duration {
self.origin.elapsed()
}
}
#[derive(Clone, Debug, Default)]
pub struct ManualClock(Arc<AtomicU64>);
impl ManualClock {
pub fn new() -> Self {
Self::default()
}
pub fn advance(&self, by: Duration) {
self.0.fetch_add(by.as_nanos() as u64, Relaxed);
}
pub fn set(&self, to: Duration) {
self.0.store(to.as_nanos() as u64, Relaxed);
}
}
impl Clock for ManualClock {
#[inline]
fn now(&self) -> Duration {
Duration::from_nanos(self.0.load(Relaxed))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_manual_clock_shares_one_timeline_across_clones() {
let clock = ManualClock::new();
let handle = clock.clone();
assert_eq!(handle.now(), Duration::ZERO);
clock.advance(Duration::from_millis(250));
assert_eq!(handle.now(), Duration::from_millis(250));
clock.set(Duration::from_secs(9));
assert_eq!(handle.now(), Duration::from_secs(9));
}
#[test]
fn the_system_clock_is_monotonic_from_its_origin() {
let clock = SystemClock::default();
let first = clock.now();
let second = clock.now();
assert!(second >= first);
}
}