From 38bf1818e48497f6c18450371d75cf987ca6670d Mon Sep 17 00:00:00 2001 From: Rico Riedel Date: Mon, 1 Aug 2022 15:34:17 +0200 Subject: [PATCH] Add timer --- src/renderer.rs | 1 + src/timer.rs | 182 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 src/timer.rs diff --git a/src/renderer.rs b/src/renderer.rs index eaf297f..6b8d6d6 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -5,6 +5,7 @@ use crate::pattern::{Config, Sampler, SamplerFactory}; use crate::printer::Printer; use crate::vec::Vector; +#[cfg_attr(test, mockall::automock)] pub trait Renderer { fn begin(&mut self) -> Result<(), Error>; fn render(&mut self, step: f32) -> Result<(), Error>; diff --git a/src/timer.rs b/src/timer.rs new file mode 100644 index 0000000..27a17a0 --- /dev/null +++ b/src/timer.rs @@ -0,0 +1,182 @@ +use crate::error::Error; +use crate::renderer::Renderer; +use std::thread; +use std::time::{Duration, Instant}; + +#[cfg_attr(test, mockall::automock)] +pub trait Clock { + fn now(&self) -> Instant; + fn sleep(&self, duration: Duration); +} + +#[derive(Default)] +pub struct ClockImpl; + +impl Clock for ClockImpl { + fn now(&self) -> Instant { + Instant::now() + } + + fn sleep(&self, duration: Duration) { + thread::sleep(duration) + } +} + +#[derive(derive_more::Constructor)] +pub struct Timer { + clock: T, + duration: Duration, + delay: Duration, +} + +impl Timer { + pub fn run(&self, mut renderer: impl Renderer) -> Result<(), Error> { + let start = self.clock.now(); + let mut now = start; + + renderer.begin()?; + + while now.duration_since(start) < self.duration { + let step = now.duration_since(start).as_secs_f32() / self.duration.as_secs_f32(); + + renderer.render(step)?; + now = self.delay(now); + } + renderer.end() + } + + fn delay(&self, begin: Instant) -> Instant { + let end = self.clock.now(); + + if self.delay > end.duration_since(begin) { + self.clock.sleep(self.delay - end.duration_since(begin)); + } + self.clock.now() + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::renderer::MockRenderer; + use mockall::predicate::eq; + use mockall::Sequence; + + #[test] + fn run_steps_correct() { + let mut clock = MockClock::new(); + let clock_seq = &mut Sequence::new(); + let begin = Instant::now(); + + clock + .expect_now() + .once() + .return_const(begin) + .in_sequence(clock_seq); + clock + .expect_now() + .times(2) + .return_const(begin + Duration::from_secs(10)) + .in_sequence(clock_seq); + clock + .expect_now() + .times(2) + .return_const(begin + Duration::from_secs(20)) + .in_sequence(clock_seq); + + let timer = Timer::new(clock, Duration::from_secs(20), Duration::from_secs(10)); + + let mut renderer = MockRenderer::new(); + let renderer_seq = &mut Sequence::new(); + + renderer + .expect_begin() + .once() + .returning(|| Ok(())) + .in_sequence(renderer_seq); + renderer + .expect_render() + .with(eq(0.0)) + .once() + .returning(|_| Ok(())) + .in_sequence(renderer_seq); + renderer + .expect_render() + .with(eq(0.5)) + .once() + .returning(|_| Ok(())) + .in_sequence(renderer_seq); + renderer + .expect_end() + .once() + .returning(|| Ok(())) + .in_sequence(renderer_seq); + + timer.run(renderer).unwrap(); + } + + #[test] + fn run_sleep_duration_correct() { + let mut clock = MockClock::new(); + let clock_seq = &mut Sequence::new(); + let begin = Instant::now(); + + clock + .expect_now() + .once() + .return_const(begin) + .in_sequence(clock_seq); + clock + .expect_now() + .once() + .return_const(begin + Duration::from_secs(4)) + .in_sequence(clock_seq); + clock + .expect_sleep() + .once() + .with(eq(Duration::from_secs(6))) + .return_const(()) + .in_sequence(clock_seq); + clock + .expect_now() + .once() + .return_const(begin + Duration::from_secs(10)) + .in_sequence(clock_seq); + + let timer = Timer::new(clock, Duration::from_secs(10), Duration::from_secs(10)); + + let mut renderer = MockRenderer::new(); + renderer.expect_begin().returning(|| Ok(())); + renderer.expect_render().returning(|_| Ok(())); + renderer.expect_end().returning(|| Ok(())); + + timer.run(renderer).unwrap(); + } + + #[test] + fn run_delay_exceeded_does_not_sleep() { + let mut clock = MockClock::new(); + let clock_seq = &mut Sequence::new(); + let begin = Instant::now(); + + clock + .expect_now() + .once() + .return_const(begin) + .in_sequence(clock_seq); + clock + .expect_now() + .times(2) + .return_const(begin + Duration::from_secs(12)) + .in_sequence(clock_seq); + + let timer = Timer::new(clock, Duration::from_secs(10), Duration::from_secs(10)); + + let mut renderer = MockRenderer::new(); + renderer.expect_begin().returning(|| Ok(())); + renderer.expect_render().returning(|_| Ok(())); + renderer.expect_end().returning(|| Ok(())); + + timer.run(renderer).unwrap(); + } +}