diff --git a/src/main.rs b/src/main.rs index 781f6d1..54d8f50 100644 --- a/src/main.rs +++ b/src/main.rs @@ -264,7 +264,7 @@ fn main() -> Result<(), Error> { let converter = ConverterImpl::new(char_converter, color_converter); let term = TerminalImpl::new(stdout()); let printer = PrinterImpl::new(term)?; - let renderer = RendererImpl::new(sampler, converter, printer); + let renderer = RendererImpl::new(sampler, converter, printer)?; let clock = ClockImpl::new(); let timer = Timer::new(clock, duration, delay); diff --git a/src/renderer.rs b/src/renderer.rs index 50bfcae..9b21535 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -3,33 +3,35 @@ use crate::pattern::*; use crate::Error; use crate::Printer; use crate::Vector; +use crossterm::style::Color; /// A renderer for an animation. #[cfg_attr(test, mockall::automock)] pub trait Renderer { - /// Prepares the terminal for the animation. - /// Call once before rendering frames. - fn begin(&mut self) -> Result<(), Error>; /// Renders the current frame and flushes. fn render(&mut self, step: f32) -> Result<(), Error>; - /// Cleans up and resets the terminal. - /// Call once after rendering frames. - fn end(&mut self) -> Result<(), Error>; } /// The implementation of [Renderer]. -#[derive(derive_more::Constructor)] -pub struct RendererImpl { +pub struct RendererImpl { sampler: T1, converter: T2, printer: T3, } -impl Renderer for RendererImpl { - fn begin(&mut self) -> Result<(), Error> { - self.printer.hide_cursor() - } +impl RendererImpl { + pub fn new(sampler: T1, converter: T2, mut printer: T3) -> Result { + printer.hide_cursor()?; + Ok(Self { + sampler, + converter, + printer, + }) + } +} + +impl Renderer for RendererImpl { fn render(&mut self, step: f32) -> Result<(), Error> { let (width, height) = self.printer.size()?; let config = Config { @@ -60,12 +62,16 @@ impl Renderer for RendererImpl Result<(), Error> { - self.printer.move_to(0, 0)?; - self.printer.clear()?; - self.printer.show_cursor()?; - self.printer.flush() +impl Drop for RendererImpl { + fn drop(&mut self) { + // Errors while dropping the renderer can be safely ignored. + self.printer.move_to(0, 0).ok(); + self.printer.set_foreground(Color::Reset).ok(); + self.printer.show_cursor().ok(); + self.printer.clear().ok(); + self.printer.flush().ok(); } } @@ -81,16 +87,22 @@ mod test { use mockall::Sequence; #[test] - fn begin() { + fn new() { let factory = MockSamplerFactory::new(); let converter = MockConverter::new(); let mut printer = MockPrinter::new(); + // Constructor printer.expect_hide_cursor().once().returning(|| Ok(())); - let mut renderer = RendererImpl::new(factory, converter, printer); + // Drop + printer.expect_move_to().returning(|_, _| Ok(())); + printer.expect_set_foreground().returning(|_| Ok(())); + printer.expect_show_cursor().returning(|| Ok(())); + printer.expect_clear().returning(|| Ok(())); + printer.expect_flush().returning(|| Ok(())); - renderer.begin().unwrap(); + drop(RendererImpl::new(factory, converter, printer)); } #[test] @@ -163,6 +175,14 @@ mod test { let seq = &mut Sequence::new(); + // Constructor + printer + .expect_hide_cursor() + .once() + .returning(|| Ok(())) + .in_sequence(seq); + + // Rendering printer .expect_move_to() .once() @@ -217,7 +237,35 @@ mod test { .returning(|| Ok(())) .in_sequence(seq); - let mut renderer = RendererImpl::new(sampler, converter, printer); + // Drop + printer + .expect_move_to() + .once() + .returning(|_, _| Ok(())) + .in_sequence(seq); + printer + .expect_set_foreground() + .with(eq(Color::Reset)) + .once() + .returning(|_| Ok(())) + .in_sequence(seq); + printer + .expect_show_cursor() + .once() + .returning(|| Ok(())) + .in_sequence(seq); + printer + .expect_clear() + .once() + .returning(|| Ok(())) + .in_sequence(seq); + printer + .expect_flush() + .once() + .returning(|| Ok(())) + .in_sequence(seq); + + let mut renderer = RendererImpl::new(sampler, converter, printer).unwrap(); renderer.render(0.0).unwrap(); } @@ -237,7 +285,17 @@ mod test { printer.expect_size().returning(|| Ok((3, 2))); printer.expect_flush().returning(|| Ok(())); - let mut renderer = RendererImpl::new(sampler, converter, printer); + // Constructor + printer.expect_hide_cursor().returning(|| Ok(())); + + // Drop + printer.expect_move_to().returning(|_, _| Ok(())); + printer.expect_set_foreground().returning(|_| Ok(())); + printer.expect_show_cursor().returning(|| Ok(())); + printer.expect_clear().returning(|| Ok(())); + printer.expect_flush().returning(|| Ok(())); + + let mut renderer = RendererImpl::new(sampler, converter, printer).unwrap(); renderer.render(0.8).unwrap(); } @@ -249,6 +307,11 @@ mod test { let mut printer = MockPrinter::new(); let seq = &mut Sequence::new(); + + // Constructor + printer.expect_hide_cursor().returning(|| Ok(())); + + // Drop printer .expect_move_to() .with(eq(0), eq(0)) @@ -256,12 +319,18 @@ mod test { .returning(|_, _| Ok(())) .in_sequence(seq); printer - .expect_clear() + .expect_set_foreground() + .with(eq(Color::Reset)) + .once() + .returning(|_| Ok(())) + .in_sequence(seq); + printer + .expect_show_cursor() .once() .returning(|| Ok(())) .in_sequence(seq); printer - .expect_show_cursor() + .expect_clear() .once() .returning(|| Ok(())) .in_sequence(seq); @@ -271,8 +340,6 @@ mod test { .returning(|| Ok(())) .in_sequence(seq); - let mut renderer = RendererImpl::new(factory, converter, printer); - - renderer.end().unwrap(); + drop(RendererImpl::new(factory, converter, printer)); } } diff --git a/src/timer.rs b/src/timer.rs index facd600..3881253 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -41,15 +41,13 @@ impl Timer { 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() + Ok(()) } /// Sleeps until the next frame starts. @@ -98,11 +96,6 @@ mod test { 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)) @@ -115,11 +108,6 @@ mod test { .once() .returning(|_| Ok(())) .in_sequence(renderer_seq); - renderer - .expect_end() - .once() - .returning(|| Ok(())) - .in_sequence(renderer_seq); timer.run(renderer).unwrap(); } @@ -155,9 +143,7 @@ mod test { 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(); } @@ -182,9 +168,7 @@ mod test { 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(); }