use indicatif::{ProgressBar, ProgressStyle}; use std::sync::Mutex; //------------------------------------------ #[derive(Clone, PartialEq)] pub enum ReportOutcome { Success, NonFatal, Fatal, } use ReportOutcome::*; impl ReportOutcome { pub fn combine(lhs: &ReportOutcome, rhs: &ReportOutcome) -> ReportOutcome { match (lhs, rhs) { (Success, rhs) => rhs.clone(), (lhs, Success) => lhs.clone(), (Fatal, _) => Fatal, (_, Fatal) => Fatal, (_, _) => NonFatal, } } } pub struct Report { outcome: Mutex, inner: Mutex>, } trait ReportInner { fn set_title(&mut self, txt: &str); fn set_sub_title(&mut self, txt: &str); fn progress(&mut self, percent: u8); fn log(&mut self, txt: &str); fn complete(&mut self); } impl Report { fn new(inner: Box) -> Report { Report { outcome: Mutex::new(Success), inner: Mutex::new(inner), } } fn update_outcome(&self, rhs: ReportOutcome) { let mut lhs = self.outcome.lock().unwrap(); *lhs = ReportOutcome::combine(&lhs, &rhs); } pub fn set_title(&self, txt: &str) { let mut inner = self.inner.lock().unwrap(); inner.set_title(txt) } pub fn set_sub_title(&self, txt: &str) { let mut inner = self.inner.lock().unwrap(); inner.set_sub_title(txt) } pub fn progress(&self, percent: u8) { let mut inner = self.inner.lock().unwrap(); inner.progress(percent) } pub fn info(&self, txt: &str) { let mut inner = self.inner.lock().unwrap(); inner.log(txt) } pub fn non_fatal(&self, txt: &str) { self.update_outcome(NonFatal); let mut inner = self.inner.lock().unwrap(); inner.log(txt) } pub fn fatal(&self, txt: &str) { self.update_outcome(Fatal); let mut inner = self.inner.lock().unwrap(); inner.log(txt) } pub fn complete(&mut self) { let mut inner = self.inner.lock().unwrap(); inner.complete(); } pub fn get_outcome(&self) -> ReportOutcome { let outcome = self.outcome.lock().unwrap(); outcome.clone() } } //------------------------------------------ #[allow(dead_code)] struct PBInner { title: String, bar: ProgressBar, } impl ReportInner for PBInner { fn set_title(&mut self, txt: &str) { self.title = txt.to_string(); } fn set_sub_title(&mut self, txt: &str) { //let mut fmt = "".to_string(); //Checking thin metadata".to_string(); //self.title.clone(); let mut fmt = "Checking thin metadata [{bar:40}] Remaining {eta}, ".to_string(); fmt.push_str(&txt); self.bar.set_style( ProgressStyle::default_bar() .template(&fmt) .progress_chars("=> "), ); } fn progress(&mut self, percent: u8) { self.bar.set_position(percent as u64); self.bar.tick(); } fn log(&mut self, txt: &str) { self.bar.println(txt); } fn complete(&mut self) { self.bar.finish(); } } pub fn mk_progress_bar_report() -> Report { Report::new(Box::new(PBInner { title: "".to_string(), bar: ProgressBar::new(100), })) } //------------------------------------------ struct SimpleInner { last_progress: std::time::SystemTime, } impl SimpleInner { fn new() -> SimpleInner { SimpleInner { last_progress: std::time::SystemTime::now(), } } } impl ReportInner for SimpleInner { fn set_title(&mut self, txt: &str) { eprintln!("{}", txt); } fn set_sub_title(&mut self, txt: &str) { eprintln!("{}", txt); } fn progress(&mut self, percent: u8) { let elapsed = self.last_progress.elapsed().unwrap(); if elapsed > std::time::Duration::from_secs(5) { eprintln!("Progress: {}%", percent); self.last_progress = std::time::SystemTime::now(); } } fn log(&mut self, txt: &str) { eprintln!("{}", txt); } fn complete(&mut self) {} } pub fn mk_simple_report() -> Report { Report::new(Box::new(SimpleInner::new())) } //------------------------------------------ struct QuietInner {} impl ReportInner for QuietInner { fn set_title(&mut self, _txt: &str) {} fn set_sub_title(&mut self, _txt: &str) {} fn progress(&mut self, _percent: u8) {} fn log(&mut self, _txt: &str) {} fn complete(&mut self) {} } pub fn mk_quiet_report() -> Report { Report::new(Box::new(QuietInner {})) } //------------------------------------------