use crate::{Clock, ControllableClock, MonotonicClock};
use chrono::{DateTime, Duration, Utc};
use parking_lot::Mutex;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct MockClock {
inner: Arc<Mutex<MockClockInner>>,
}
#[derive(Debug)]
struct MockClockInner {
monotonic_clock: MonotonicClock,
create_time: i64,
epoch: i64,
millis_to_add: i64,
millis_to_add_each_time: i64,
add_every_time: bool,
}
impl MockClock {
pub fn new() -> Self {
let monotonic_clock = MonotonicClock::new();
let create_time = monotonic_clock.millis();
MockClock {
inner: Arc::new(Mutex::new(MockClockInner {
monotonic_clock,
create_time,
epoch: create_time,
millis_to_add: 0,
millis_to_add_each_time: 0,
add_every_time: false,
})),
}
}
pub fn add_millis(&self, millis: i64, add_every_time: bool) {
let mut inner = self.inner.lock();
if add_every_time {
inner.millis_to_add_each_time = millis;
inner.add_every_time = true;
} else {
inner.millis_to_add += millis;
}
}
}
impl Default for MockClock {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Clock for MockClock {
fn millis(&self) -> i64 {
let mut inner = self.inner.lock();
let elapsed = inner.monotonic_clock.millis() - inner.create_time;
let result = inner.epoch + elapsed + inner.millis_to_add;
if inner.add_every_time {
inner.millis_to_add += inner.millis_to_add_each_time;
}
result
}
}
impl ControllableClock for MockClock {
fn set_time(&self, instant: DateTime<Utc>) {
let mut inner = self.inner.lock();
let current_monotonic = inner.monotonic_clock.millis();
let elapsed = current_monotonic - inner.create_time;
inner.epoch = instant.timestamp_millis() - elapsed;
inner.millis_to_add = 0;
inner.millis_to_add_each_time = 0;
inner.add_every_time = false;
}
#[inline]
fn add_duration(&self, duration: Duration) {
let millis = duration.num_milliseconds();
self.add_millis(millis, false);
}
fn reset(&self) {
let mut inner = self.inner.lock();
inner.epoch = inner.create_time;
inner.millis_to_add = 0;
inner.millis_to_add_each_time = 0;
inner.add_every_time = false;
}
}