use std::time::{Duration, Instant};
#[derive(Debug, Default)]
pub(crate) struct ElapsedTimer {
start_time: Option<Instant>,
}
impl ElapsedTimer {
pub(crate) fn is_running(&self) -> bool {
self.start_time.is_some()
}
pub(crate) fn elapsed_since_start(&mut self, duration: Duration) -> bool {
let now = Instant::now();
let start = *self.start_time.get_or_insert(now);
now.duration_since(start) >= duration
}
pub(crate) fn reset(&mut self) {
self.start_time = None;
}
}
macro_rules! reset_timer_field {
($field:ident) => {
fn reset_self(&mut self) {
self.$field.reset();
}
};
}
pub(crate) use reset_timer_field;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_timer_is_not_running() {
let timer = ElapsedTimer::default();
assert!(!timer.is_running());
}
#[test]
fn elapsed_since_start_starts_the_clock_on_first_call() {
let mut timer = ElapsedTimer::default();
assert!(!timer.elapsed_since_start(Duration::from_secs(60)));
assert!(timer.is_running());
}
#[test]
fn elapsed_since_start_reports_elapsed_once_duration_is_zero() {
let mut timer = ElapsedTimer::default();
assert!(timer.elapsed_since_start(Duration::ZERO));
}
#[test]
fn elapsed_since_start_keeps_the_original_start_time_across_calls() {
let mut timer = ElapsedTimer::default();
assert!(!timer.elapsed_since_start(Duration::from_millis(50)));
std::thread::sleep(Duration::from_millis(75));
assert!(timer.elapsed_since_start(Duration::from_millis(50)));
}
#[test]
fn reset_clears_the_clock() {
let mut timer = ElapsedTimer::default();
timer.elapsed_since_start(Duration::from_secs(60));
assert!(timer.is_running());
timer.reset();
assert!(!timer.is_running());
}
}