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 converter = ConverterImpl::new(char_converter, color_converter);
let term = TerminalImpl::new(stdout()); let term = TerminalImpl::new(stdout());
let printer = PrinterImpl::new(term)?; let printer = PrinterImpl::new(term)?;
let renderer = RendererImpl::new(sampler, converter, printer); let renderer = RendererImpl::new(sampler, converter, printer)?;
let clock = ClockImpl::new(); let clock = ClockImpl::new();
let timer = Timer::new(clock, duration, delay); let timer = Timer::new(clock, duration, delay);

View File

@ -3,33 +3,35 @@ use crate::pattern::*;
use crate::Error; use crate::Error;
use crate::Printer; use crate::Printer;
use crate::Vector; use crate::Vector;
use crossterm::style::Color;
/// A renderer for an animation. /// A renderer for an animation.
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait Renderer { 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. /// Renders the current frame and flushes.
fn render(&mut self, step: f32) -> Result<(), Error>; 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]. /// The implementation of [Renderer].
#[derive(derive_more::Constructor)] pub struct RendererImpl<T1, T2, T3: Printer> {
pub struct RendererImpl<T1, T2, T3> {
sampler: T1, sampler: T1,
converter: T2, converter: T2,
printer: T3, printer: T3,
} }
impl<T1: SamplerFactory, T2: Converter, T3: Printer> Renderer for RendererImpl<T1, T2, T3> { impl<T1, T2, T3: Printer> RendererImpl<T1, T2, T3> {
fn begin(&mut self) -> Result<(), Error> { pub fn new(sampler: T1, converter: T2, mut printer: T3) -> Result<Self, Error> {
self.printer.hide_cursor() 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> { fn render(&mut self, step: f32) -> Result<(), Error> {
let (width, height) = self.printer.size()?; let (width, height) = self.printer.size()?;
let config = Config { let config = Config {
@ -60,12 +62,16 @@ impl<T1: SamplerFactory, T2: Converter, T3: Printer> Renderer for RendererImpl<T
} }
self.printer.flush() self.printer.flush()
} }
}
fn end(&mut self) -> Result<(), Error> { impl<T1, T2, T3: Printer> Drop for RendererImpl<T1, T2, T3> {
self.printer.move_to(0, 0)?; fn drop(&mut self) {
self.printer.clear()?; // Errors while dropping the renderer can be safely ignored.
self.printer.show_cursor()?; self.printer.move_to(0, 0).ok();
self.printer.flush() 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; use mockall::Sequence;
#[test] #[test]
fn begin() { fn new() {
let factory = MockSamplerFactory::new(); let factory = MockSamplerFactory::new();
let converter = MockConverter::new(); let converter = MockConverter::new();
let mut printer = MockPrinter::new(); let mut printer = MockPrinter::new();
// Constructor
printer.expect_hide_cursor().once().returning(|| Ok(())); 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] #[test]
@ -163,6 +175,14 @@ mod test {
let seq = &mut Sequence::new(); let seq = &mut Sequence::new();
// Constructor
printer
.expect_hide_cursor()
.once()
.returning(|| Ok(()))
.in_sequence(seq);
// Rendering
printer printer
.expect_move_to() .expect_move_to()
.once() .once()
@ -217,7 +237,35 @@ mod test {
.returning(|| Ok(())) .returning(|| Ok(()))
.in_sequence(seq); .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(); renderer.render(0.0).unwrap();
} }
@ -237,7 +285,17 @@ mod test {
printer.expect_size().returning(|| Ok((3, 2))); printer.expect_size().returning(|| Ok((3, 2)));
printer.expect_flush().returning(|| Ok(())); 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(); renderer.render(0.8).unwrap();
} }
@ -249,6 +307,11 @@ mod test {
let mut printer = MockPrinter::new(); let mut printer = MockPrinter::new();
let seq = &mut Sequence::new(); let seq = &mut Sequence::new();
// Constructor
printer.expect_hide_cursor().returning(|| Ok(()));
// Drop
printer printer
.expect_move_to() .expect_move_to()
.with(eq(0), eq(0)) .with(eq(0), eq(0))
@ -256,12 +319,18 @@ mod test {
.returning(|_, _| Ok(())) .returning(|_, _| Ok(()))
.in_sequence(seq); .in_sequence(seq);
printer printer
.expect_clear() .expect_set_foreground()
.with(eq(Color::Reset))
.once()
.returning(|_| Ok(()))
.in_sequence(seq);
printer
.expect_show_cursor()
.once() .once()
.returning(|| Ok(())) .returning(|| Ok(()))
.in_sequence(seq); .in_sequence(seq);
printer printer
.expect_show_cursor() .expect_clear()
.once() .once()
.returning(|| Ok(())) .returning(|| Ok(()))
.in_sequence(seq); .in_sequence(seq);
@ -271,8 +340,6 @@ mod test {
.returning(|| Ok(())) .returning(|| Ok(()))
.in_sequence(seq); .in_sequence(seq);
let mut renderer = RendererImpl::new(factory, converter, printer); drop(RendererImpl::new(factory, converter, printer));
renderer.end().unwrap();
} }
} }

View File

@ -41,15 +41,13 @@ impl<T: Clock> Timer<T> {
let start = self.clock.now(); let start = self.clock.now();
let mut now = start; let mut now = start;
renderer.begin()?;
while now.duration_since(start) < self.duration { while now.duration_since(start) < self.duration {
let step = now.duration_since(start).as_secs_f32() / self.duration.as_secs_f32(); let step = now.duration_since(start).as_secs_f32() / self.duration.as_secs_f32();
renderer.render(step)?; renderer.render(step)?;
now = self.delay(now); now = self.delay(now);
} }
renderer.end() Ok(())
} }
/// Sleeps until the next frame starts. /// Sleeps until the next frame starts.
@ -98,11 +96,6 @@ mod test {
let mut renderer = MockRenderer::new(); let mut renderer = MockRenderer::new();
let renderer_seq = &mut Sequence::new(); let renderer_seq = &mut Sequence::new();
renderer
.expect_begin()
.once()
.returning(|| Ok(()))
.in_sequence(renderer_seq);
renderer renderer
.expect_render() .expect_render()
.with(eq(0.0)) .with(eq(0.0))
@ -115,11 +108,6 @@ mod test {
.once() .once()
.returning(|_| Ok(())) .returning(|_| Ok(()))
.in_sequence(renderer_seq); .in_sequence(renderer_seq);
renderer
.expect_end()
.once()
.returning(|| Ok(()))
.in_sequence(renderer_seq);
timer.run(renderer).unwrap(); timer.run(renderer).unwrap();
} }
@ -155,9 +143,7 @@ mod test {
let timer = Timer::new(clock, Duration::from_secs(10), Duration::from_secs(10)); let timer = Timer::new(clock, Duration::from_secs(10), Duration::from_secs(10));
let mut renderer = MockRenderer::new(); let mut renderer = MockRenderer::new();
renderer.expect_begin().returning(|| Ok(()));
renderer.expect_render().returning(|_| Ok(())); renderer.expect_render().returning(|_| Ok(()));
renderer.expect_end().returning(|| Ok(()));
timer.run(renderer).unwrap(); timer.run(renderer).unwrap();
} }
@ -182,9 +168,7 @@ mod test {
let timer = Timer::new(clock, Duration::from_secs(10), Duration::from_secs(10)); let timer = Timer::new(clock, Duration::from_secs(10), Duration::from_secs(10));
let mut renderer = MockRenderer::new(); let mut renderer = MockRenderer::new();
renderer.expect_begin().returning(|| Ok(()));
renderer.expect_render().returning(|_| Ok(())); renderer.expect_render().returning(|_| Ok(()));
renderer.expect_end().returning(|| Ok(()));
timer.run(renderer).unwrap(); timer.run(renderer).unwrap();
} }