pub trait ProgressReporter: Send + Sync {
fn set_message(&self, message: &str);
fn set_progress(&self, current: u64, total: u64);
fn finish_success(&self, message: &str);
fn finish_error(&self, message: &str);
fn inc(&self, delta: u64) {
let _ = delta;
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct NullReporter;
impl ProgressReporter for NullReporter {
fn set_message(&self, _message: &str) {}
fn set_progress(&self, _current: u64, _total: u64) {}
fn finish_success(&self, _message: &str) {}
fn finish_error(&self, _message: &str) {}
}
impl ProgressReporter for () {
fn set_message(&self, _message: &str) {}
fn set_progress(&self, _current: u64, _total: u64) {}
fn finish_success(&self, _message: &str) {}
fn finish_error(&self, _message: &str) {}
}
pub struct FnReporter<F>
where
F: Fn(&str) + Send + Sync,
{
callback: F,
}
impl<F> FnReporter<F>
where
F: Fn(&str) + Send + Sync,
{
pub fn new(callback: F) -> Self {
Self { callback }
}
}
impl<F> ProgressReporter for FnReporter<F>
where
F: Fn(&str) + Send + Sync,
{
fn set_message(&self, message: &str) {
(self.callback)(message);
}
fn set_progress(&self, current: u64, total: u64) {
let msg = format!("{}/{}", current, total);
(self.callback)(&msg);
}
fn finish_success(&self, message: &str) {
(self.callback)(message);
}
fn finish_error(&self, message: &str) {
(self.callback)(message);
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used)]
use super::*;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
#[test]
fn test_null_reporter_is_silent() {
let reporter = NullReporter;
reporter.set_message("test");
reporter.set_progress(1, 10);
reporter.finish_success("done");
reporter.finish_error("error");
}
#[test]
fn test_unit_as_reporter() {
let reporter: &dyn ProgressReporter = &();
reporter.set_message("test");
reporter.set_progress(1, 10);
reporter.finish_success("done");
}
#[test]
fn test_fn_reporter_calls_callback() {
let count = Arc::new(AtomicUsize::new(0));
let count_clone = count.clone();
let reporter = FnReporter::new(move |_msg| {
count_clone.fetch_add(1, Ordering::SeqCst);
});
reporter.set_message("one");
reporter.set_progress(1, 10);
reporter.finish_success("done");
assert_eq!(count.load(Ordering::SeqCst), 3);
}
}