Add timer

This commit is contained in:
Rico Riedel 2022-08-01 15:34:17 +02:00
parent 2943a2514b
commit 38bf1818e4
No known key found for this signature in database
GPG Key ID: 75AC868575DE7B18
2 changed files with 183 additions and 0 deletions

View File

@ -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>;

182
src/timer.rs Normal file
View File

@ -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<T> {
clock: T,
duration: Duration,
delay: Duration,
}
impl<T: Clock> Timer<T> {
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();
}
}