use core::time::Duration;
use crate::{extent::ToExtent, Clock, Extent, Timestamp};
#[derive(Clone, Copy)]
pub struct Timer<C> {
start: Option<Timestamp>,
clock: C,
}
impl<C: Clock> Timer<C> {
pub fn start(clock: C) -> Self {
Timer {
start: clock.now(),
clock,
}
}
pub fn start_timestamp(&self) -> Option<Timestamp> {
self.start
}
pub fn extent(&self) -> Option<Extent> {
let end = self.clock.now();
match (self.start, end) {
(Some(start), Some(end)) => Some(Extent::range(start..end)),
_ => None,
}
}
pub fn elapsed(&self) -> Option<Duration> {
self.extent().and_then(|extent| extent.len())
}
pub fn by_ref(&self) -> Timer<&C> {
Timer {
start: self.start,
clock: &self.clock,
}
}
}
impl<C: Clock> ToExtent for Timer<C> {
fn to_extent(&self) -> Option<Extent> {
self.extent()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::Cell;
struct MyClock(Cell<Timestamp>);
impl Clock for MyClock {
fn now(&self) -> Option<Timestamp> {
Some(self.0.get())
}
}
#[test]
fn timer_forwards() {
let clock = MyClock(Cell::new(
Timestamp::from_unix(Duration::from_secs(0)).unwrap(),
));
let timer = Timer::start(&clock);
assert_eq!(
Timestamp::from_unix(Duration::from_secs(0)).unwrap(),
timer.start_timestamp().unwrap()
);
assert_eq!(Duration::from_secs(0), timer.elapsed().unwrap());
assert_eq!(
Timestamp::from_unix(Duration::from_secs(0)).unwrap()
..Timestamp::from_unix(Duration::from_secs(0)).unwrap(),
timer.extent().unwrap().as_range().unwrap().clone()
);
clock
.0
.set(Timestamp::from_unix(Duration::from_secs(1)).unwrap());
assert_eq!(Duration::from_secs(1), timer.elapsed().unwrap());
assert_eq!(
Timestamp::from_unix(Duration::from_secs(0)).unwrap()
..Timestamp::from_unix(Duration::from_secs(1)).unwrap(),
timer.extent().unwrap().as_range().unwrap().clone()
);
}
#[test]
fn timer_backwards() {
let clock = MyClock(Cell::new(
Timestamp::from_unix(Duration::from_secs(1)).unwrap(),
));
let timer = Timer::start(&clock);
clock
.0
.set(Timestamp::from_unix(Duration::from_secs(0)).unwrap());
assert_eq!(None, timer.elapsed());
assert_eq!(
Timestamp::from_unix(Duration::from_secs(1)).unwrap()
..Timestamp::from_unix(Duration::from_secs(0)).unwrap(),
timer.extent().unwrap().as_range().unwrap().clone()
);
}
#[test]
fn timer_empty() {
let timer = Timer::start(crate::Empty);
assert!(timer.start_timestamp().is_none());
assert!(timer.elapsed().is_none());
}
}