clocks 0.0.1

A testable source of time
Documentation
use chrono::{DateTime, Duration, Utc};
use std::sync::{Arc, Mutex};

#[derive(Clone, Debug)]
pub struct Clock {
    inner: ClockInner,
}

impl Clock {
    pub fn new() -> Self {
        Self {
            inner: ClockInner::Wall,
        }
    }

    pub fn new_fake(start: DateTime<Utc>) -> Self {
        Self {
            inner: ClockInner::Fake(FakeClock::new(start)),
        }
    }

    pub fn now(&self) -> DateTime<Utc> {
        match &self.inner {
            ClockInner::Wall => Utc::now(),
            ClockInner::Fake(f) => f.now(),
        }
    }

    pub fn is_fake(&self) -> bool {
        match &self.inner {
            ClockInner::Wall => false,
            ClockInner::Fake(_) => true,
        }
    }

    pub fn advance(&mut self, duration: Duration) -> DateTime<Utc> {
        match &self.inner {
            ClockInner::Wall => panic!("Attempted to advance system clock"),
            ClockInner::Fake(f) => f.advance(duration),
        }
    }
}

impl Default for Clock {
    fn default() -> Self {
        Self::new()
    }
}

#[derive(Clone, Debug)]
enum ClockInner {
    Wall,
    Fake(FakeClock),
}

#[derive(Clone, Debug)]
struct FakeClock {
    now: Arc<Mutex<DateTime<Utc>>>,
}

impl FakeClock {
    pub(crate) fn new(start: DateTime<Utc>) -> Self {
        Self {
            now: Arc::new(Mutex::new(start)),
        }
    }

    pub(crate) fn now(&self) -> DateTime<Utc> {
        *self.now.lock().unwrap()
    }

    pub(crate) fn advance(&self, duration: Duration) -> DateTime<Utc> {
        let mut v = self.now.lock().unwrap();
        *v = *v + duration;
        *v
    }
}