Adhere to RAII

This commit is contained in:
Rico Riedel 2022-11-22 21:51:09 +01:00
parent 1eddc2e3a2
commit edb429ed43
No known key found for this signature in database
GPG Key ID: 75AC868575DE7B18
3 changed files with 96 additions and 45 deletions

View File

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

View File

@ -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<T1, T2, T3> {
pub struct RendererImpl<T1, T2, T3: Printer> {
sampler: T1,
converter: T2,
printer: T3,
}
impl<T1: SamplerFactory, T2: Converter, T3: Printer> Renderer for RendererImpl<T1, T2, T3> {
fn begin(&mut self) -> Result<(), Error> {
self.printer.hide_cursor()
}
impl<T1, T2, T3: Printer> RendererImpl<T1, T2, T3> {
pub fn new(sampler: T1, converter: T2, mut printer: T3) -> Result<Self, Error> {
printer.hide_cursor()?;
Ok(Self {
sampler,
converter,
printer,
})
}
}
impl<T1: SamplerFactory, T2: Converter, T3: Printer> Renderer for RendererImpl<T1, T2, T3> {
fn render(&mut self, step: f32) -> Result<(), Error> {
let (width, height) = self.printer.size()?;
let config = Config {
@ -60,12 +62,16 @@ impl<T1: SamplerFactory, T2: Converter, T3: Printer> Renderer for RendererImpl<T
}
self.printer.flush()
}
}
fn end(&mut self) -> Result<(), Error> {
self.printer.move_to(0, 0)?;
self.printer.clear()?;
self.printer.show_cursor()?;
self.printer.flush()
impl<T1, T2, T3: Printer> Drop for RendererImpl<T1, T2, T3> {
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));
}
}

View File

@ -41,15 +41,13 @@ impl<T: Clock> Timer<T> {
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();
}