mirror of
https://github.com/ricoriedel/wipe.git
synced 2024-12-22 14:16:48 +00:00
Add timer
This commit is contained in:
parent
2943a2514b
commit
38bf1818e4
@ -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
182
src/timer.rs
Normal 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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user