use std::io::Write;
use indicatif::{ProgressBar, ProgressStyle};
pub trait ProgressReport {
fn set_length(&self, len: u64);
fn inc(&self, n: u64);
fn position(&self) -> u64;
fn set_entry(&self, name: &str);
fn finish(&self);
}
pub struct NoProgress;
impl ProgressReport for NoProgress {
fn set_length(&self, _len: u64) {}
fn inc(&self, _n: u64) {}
fn position(&self) -> u64 { 0 }
fn set_entry(&self, _name: &str) {}
fn finish(&self) {}
}
pub struct BarProgress {
bar: ProgressBar,
}
impl BarProgress {
pub fn bytes(total: u64) -> Self {
let bar = ProgressBar::new(total);
bar.set_style(
ProgressStyle::default_bar()
.template("{bar:40.cyan/blue} {bytes}/{total_bytes} ({eta}) {msg}")
.unwrap_or_else(|_| ProgressStyle::default_bar()),
);
Self { bar }
}
pub fn spinner() -> Self {
let bar = ProgressBar::new_spinner();
bar.set_style(
ProgressStyle::default_spinner()
.template("{spinner:.green} {bytes} ({bytes_per_sec}) {msg}")
.unwrap_or_else(|_| ProgressStyle::default_spinner()),
);
bar.enable_steady_tick(std::time::Duration::from_millis(120));
Self { bar }
}
}
impl BarProgress {
pub fn hidden() -> Self {
Self { bar: ProgressBar::hidden() }
}
}
impl ProgressReport for BarProgress {
fn set_length(&self, len: u64) {
self.bar.set_length(len);
}
fn inc(&self, n: u64) {
self.bar.inc(n);
}
fn position(&self) -> u64 {
self.bar.position()
}
fn set_entry(&self, name: &str) {
self.bar.set_message(name.to_owned());
}
fn finish(&self) {
self.bar.finish_and_clear();
}
}
pub struct VerboseReport<'a> {
inner: &'a dyn ProgressReport,
}
impl<'a> VerboseReport<'a> {
pub fn new(inner: &'a dyn ProgressReport) -> Self {
Self { inner }
}
}
impl ProgressReport for VerboseReport<'_> {
fn set_length(&self, len: u64) {
self.inner.set_length(len);
}
fn inc(&self, n: u64) {
self.inner.inc(n);
}
fn position(&self) -> u64 {
self.inner.position()
}
fn set_entry(&self, name: &str) {
let mut stderr = std::io::stderr().lock();
let _ = writeln!(stderr, "{name}");
self.inner.set_entry(name);
}
fn finish(&self) {
self.inner.finish();
}
}