mirror of
https://github.com/ricoriedel/wipe.git
synced 2024-12-22 22:26:41 +00:00
Add cancel feature
This commit is contained in:
parent
19461dde26
commit
1e4403b5cb
74
Cargo.lock
generated
74
Cargo.lock
generated
@ -43,6 +43,12 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cancellation"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7a879c84c21f354f13535f87ad119ac3be22ebb9097b552a0af6a78f86628c4"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@ -51,26 +57,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.16"
|
||||
version = "4.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9"
|
||||
checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.2.15"
|
||||
version = "4.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ba52acd3b0a5c33aeada5cdaa3267cdc7c594a98731d4268cdc1532f4264cb4"
|
||||
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
@ -81,9 +85,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
@ -96,9 +100,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.24.0"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab9f7409c70a38a56216480fba371ee460207dd8926ccf5b4160591759559170"
|
||||
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
@ -119,6 +123,16 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.17"
|
||||
@ -176,12 +190,6 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.0"
|
||||
@ -197,16 +205,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.3"
|
||||
@ -224,9 +222,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
version = "0.2.137"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@ -292,6 +290,18 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "normalize-line-endings"
|
||||
version = "0.3.0"
|
||||
@ -565,12 +575,6 @@ version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.3"
|
||||
@ -668,8 +672,10 @@ name = "wipe"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"cancellation",
|
||||
"clap",
|
||||
"crossterm",
|
||||
"ctrlc",
|
||||
"derive_more",
|
||||
"mockall",
|
||||
"rand",
|
||||
|
@ -8,8 +8,10 @@ repository = "https://github.com/ricoriedel/wipe"
|
||||
authors = ["Rico Riedel <rico.riedel@protonmail.ch>"]
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "3.2", features = ["derive"] }
|
||||
crossterm = "0.24"
|
||||
clap = { version = "4.0.26", features = ["derive"] }
|
||||
crossterm = "0.25.0"
|
||||
ctrlc = "3.2.3"
|
||||
cancellation = "0.1.0"
|
||||
derive_more = "0.99"
|
||||
rand = "0.8"
|
||||
|
||||
|
@ -21,6 +21,12 @@ impl From<&str> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ctrlc::Error> for Error {
|
||||
fn from(err: ctrlc::Error) -> Self {
|
||||
Error(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::Error;
|
||||
use crate::Renderer;
|
||||
use cancellation::CancellationToken;
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
@ -29,23 +30,23 @@ impl Clock for ClockImpl {
|
||||
|
||||
/// A timer for rendering.
|
||||
#[derive(derive_more::Constructor)]
|
||||
pub struct Timer<T> {
|
||||
pub struct Executor<T> {
|
||||
clock: T,
|
||||
duration: Duration,
|
||||
delay: Duration,
|
||||
}
|
||||
|
||||
impl<T: Clock> Timer<T> {
|
||||
impl<T: Clock> Executor<T> {
|
||||
/// Runs the animation main loop.
|
||||
pub fn run(&self, mut renderer: impl Renderer) -> Result<(), Error> {
|
||||
pub fn run(&self, mut renderer: impl Renderer, token: &CancellationToken) -> Result<(), Error> {
|
||||
let start = self.clock.now();
|
||||
let mut now = start;
|
||||
let mut tick = start;
|
||||
|
||||
while now.duration_since(start) < self.duration {
|
||||
let step = now.duration_since(start).as_secs_f32() / self.duration.as_secs_f32();
|
||||
while !token.is_canceled() && tick.duration_since(start) < self.duration {
|
||||
let step = tick.duration_since(start).as_secs_f32() / self.duration.as_secs_f32();
|
||||
|
||||
renderer.render(step)?;
|
||||
now = self.delay(now);
|
||||
tick = self.delay(tick);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -66,6 +67,7 @@ impl<T: Clock> Timer<T> {
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::MockRenderer;
|
||||
use cancellation::CancellationTokenSource;
|
||||
use mockall::predicate::eq;
|
||||
use mockall::Sequence;
|
||||
|
||||
@ -91,7 +93,7 @@ mod test {
|
||||
.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 timer = Executor::new(clock, Duration::from_secs(20), Duration::from_secs(10));
|
||||
|
||||
let mut renderer = MockRenderer::new();
|
||||
let renderer_seq = &mut Sequence::new();
|
||||
@ -109,7 +111,7 @@ mod test {
|
||||
.returning(|_| Ok(()))
|
||||
.in_sequence(renderer_seq);
|
||||
|
||||
timer.run(renderer).unwrap();
|
||||
timer.run(renderer, CancellationToken::none()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -140,12 +142,12 @@ mod test {
|
||||
.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 timer = Executor::new(clock, Duration::from_secs(10), Duration::from_secs(10));
|
||||
|
||||
let mut renderer = MockRenderer::new();
|
||||
renderer.expect_render().returning(|_| Ok(()));
|
||||
|
||||
timer.run(renderer).unwrap();
|
||||
timer.run(renderer, CancellationToken::none()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -165,11 +167,30 @@ mod test {
|
||||
.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 timer = Executor::new(clock, Duration::from_secs(10), Duration::from_secs(10));
|
||||
|
||||
let mut renderer = MockRenderer::new();
|
||||
renderer.expect_render().returning(|_| Ok(()));
|
||||
|
||||
timer.run(renderer).unwrap();
|
||||
timer.run(renderer, CancellationToken::none()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_canceled_aborts() {
|
||||
let mut clock = MockClock::new();
|
||||
let mut renderer = MockRenderer::new();
|
||||
let src = CancellationTokenSource::new();
|
||||
let token = src.token().clone();
|
||||
|
||||
clock.expect_now().return_const(Instant::now());
|
||||
clock.expect_sleep().once().return_const(());
|
||||
renderer.expect_render().once().returning(move |_| {
|
||||
src.cancel();
|
||||
|
||||
Ok(())
|
||||
});
|
||||
let timer = Executor::new(clock, Duration::from_secs(10), Duration::from_secs(1));
|
||||
|
||||
timer.run(renderer, &token).unwrap();
|
||||
}
|
||||
}
|
15
src/main.rs
15
src/main.rs
@ -3,22 +3,23 @@ pub mod pattern;
|
||||
pub mod transform;
|
||||
|
||||
mod error;
|
||||
mod exec;
|
||||
mod printer;
|
||||
mod renderer;
|
||||
mod term;
|
||||
mod timer;
|
||||
mod vec;
|
||||
|
||||
pub use error::*;
|
||||
pub use exec::*;
|
||||
pub use printer::*;
|
||||
pub use renderer::*;
|
||||
pub use term::*;
|
||||
pub use timer::*;
|
||||
pub use vec::*;
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::pattern::*;
|
||||
use crate::transform::*;
|
||||
use cancellation::CancellationTokenSource;
|
||||
use clap::builder::NonEmptyStringValueParser;
|
||||
use clap::{value_parser, Parser, ValueEnum};
|
||||
use crossterm::style::Color;
|
||||
@ -267,9 +268,15 @@ fn main() -> Result<(), Error> {
|
||||
let renderer = RendererImpl::new(sampler, converter, printer)?;
|
||||
|
||||
let clock = ClockImpl::new();
|
||||
let timer = Timer::new(clock, duration, delay);
|
||||
let executor = Executor::new(clock, duration, delay);
|
||||
|
||||
timer.run(renderer)
|
||||
let src = CancellationTokenSource::new();
|
||||
let token = src.token().clone();
|
||||
|
||||
ctrlc::set_handler(move || {
|
||||
src.cancel();
|
||||
})?;
|
||||
executor.run(renderer, &token)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
Loading…
Reference in New Issue
Block a user