use std::sync::Arc;
pub trait ProgressHandle: Send + Sync {
fn inc(&self, delta: u64);
fn set_message(&self, _message: &str) {}
fn finish(&self) {}
}
pub trait ProgressReporter: Send + Sync {
fn start(&self, total: u64, label: &str) -> Box<dyn ProgressHandle>;
}
pub struct NoopHandle;
impl ProgressHandle for NoopHandle {
fn inc(&self, _delta: u64) {}
}
#[derive(Clone, Default)]
pub struct SharedProgress(Option<Arc<dyn ProgressReporter>>);
impl SharedProgress {
pub fn new(reporter: Arc<dyn ProgressReporter>) -> Self {
Self(Some(reporter))
}
pub fn none() -> Self {
Self(None)
}
pub fn as_ref(&self) -> Option<&dyn ProgressReporter> {
self.0.as_deref()
}
}
#[cfg(feature = "progress")]
mod indicatif_impl {
use super::{ProgressHandle, ProgressReporter};
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
pub struct IndicatifReporter {
multi: MultiProgress,
}
impl IndicatifReporter {
pub fn new(multi: MultiProgress) -> Self {
Self { multi }
}
}
impl ProgressReporter for IndicatifReporter {
fn start(&self, total: u64, label: &str) -> Box<dyn ProgressHandle> {
let bar = self.multi.add(ProgressBar::new(total));
let style = ProgressStyle::with_template(
"{prefix}: [{elapsed_precise}] {bar:40.cyan/blue} {msg} ({binary_bytes:>7}/{binary_total_bytes:7})",
)
.expect("invariant: progress template literal is valid")
.progress_chars("##-");
bar.set_style(style);
bar.set_prefix(label.to_string());
Box::new(IndicatifHandle { bar })
}
}
pub struct IndicatifHandle {
bar: ProgressBar,
}
impl ProgressHandle for IndicatifHandle {
fn inc(&self, delta: u64) {
self.bar.inc(delta);
}
fn set_message(&self, message: &str) {
self.bar.set_message(message.to_string());
}
fn finish(&self) {
self.bar.finish_with_message("done");
}
}
impl Drop for IndicatifHandle {
fn drop(&mut self) {
if !self.bar.is_finished() {
self.bar.finish_with_message("done");
}
}
}
}
#[cfg(feature = "progress")]
pub use indicatif_impl::{IndicatifHandle, IndicatifReporter};