pub type Progress = std::sync::Arc<dyn Reporter>;
pub trait Reporter: Send + Sync {
fn setup(&self, max_progress: Option<u64>, message: &str);
fn progress(&self, current: u64);
fn set_message(&self, message: &str);
fn done(&self);
}
pub trait Factory {
fn create_reporter(&self) -> crate::Progress;
fn join(&self);
}
#[derive(Default)]
pub struct Noop {}
impl Reporter for Noop {
fn setup(&self, _: Option<u64>, _: &str) {}
fn progress(&self, _: u64) {}
fn set_message(&self, _: &str) {}
fn done(&self) {}
}
impl Noop {
#[must_use]
pub fn create() -> crate::Progress {
std::sync::Arc::new(Self {})
}
}
impl Factory for Noop {
fn create_reporter(&self) -> crate::Progress {
Self::create()
}
fn join(&self) {}
}
#[cfg(feature = "tui")]
mod tui {
pub struct Tui {
progress_group: indicatif::MultiProgress,
}
impl Default for Tui {
fn default() -> Self {
Self {
progress_group: indicatif::MultiProgress::with_draw_target(
indicatif::ProgressDrawTarget::stderr_with_hz(4),
),
}
}
}
impl super::Factory for Tui {
fn create_reporter(&self) -> crate::Progress {
std::sync::Arc::new(TuiBar {
progress_bar: std::sync::Mutex::new(
self.progress_group.add(indicatif::ProgressBar::new(1)),
),
})
}
fn join(&self) {
self.progress_group
.join()
.expect("No ui if this fails, which is OK for us");
}
}
struct TuiBar {
progress_bar: std::sync::Mutex<indicatif::ProgressBar>,
}
impl super::Reporter for TuiBar {
fn setup(&self, max_progress: Option<u64>, message: &str) {
let lock = self.progress_bar.lock().unwrap();
if let Some(t) = max_progress {
lock.set_length(t);
lock.set_style(indicatif::ProgressStyle::default_bar()
.template("[{bar:20.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta}) - {msg}")
.progress_chars("#- "));
lock.set_message(message);
lock.reset_eta();
} else {
lock.set_style(
indicatif::ProgressStyle::default_spinner()
.tick_strings(&[
"▹▹▹▹▹",
"▸▹▹▹▹",
"▹▸▹▹▹",
"▹▹▸▹▹",
"▹▹▹▸▹",
"▹▹▹▹▸",
"▪▪▪▪▪",
])
.template("{spinner:.blue} {msg}"),
);
lock.set_message(message)
};
}
fn progress(&self, current: u64) {
let lock = self.progress_bar.lock().unwrap();
lock.set_position(current);
}
fn set_message(&self, message: &str) {
let lock = self.progress_bar.lock().unwrap();
lock.set_message(message);
}
fn done(&self) {
let lock = self.progress_bar.lock().unwrap();
lock.finish();
}
}
}
#[cfg(feature = "tui")]
pub use tui::Tui;