use std::sync::Mutex; struct StatusReportData { files: usize, items: usize, total_files: usize, total_items: usize, changed_items: usize, last_file: String, last_item: String, } impl StatusReportData { fn print(&self, clear: bool) { if clear { print!("\x1b[1F\x1b[2K\x1b[1F\x1b[2K"); } println!("{}/{} files ({})", self.files, self.total_files, self.last_file); println!("{}/{} ({}) items ({})", self.items, self.total_items, self.changed_items, self.last_item); } } pub struct StatusReport(Mutex); impl StatusReport { pub fn new(total_files: usize, total_items: usize) -> Self { Self(Mutex::new(StatusReportData { files: 0, items: 0, total_files, total_items, changed_items: 0, last_file: "".to_string(), last_item: "".to_string(), })) } pub fn enter_file(&self, f: &str) { let mut m = self.0.lock().unwrap(); m.files += 1; m.last_file = f.to_string(); m.print(m.files > 1 || m.items >= 1); } fn enter_item(&self, i: String) { let mut m = self.0.lock().unwrap(); m.items += 1; m.last_item = i; m.print(m.files >= 1 || m.items > 1); } pub fn update_item(&self, i: String) { let mut m = self.0.lock().unwrap(); m.last_item = i; m.print(true); } pub fn changed_item(&self) { let mut m = self.0.lock().unwrap(); m.changed_items += 1; m.print(true); } fn skip_items(&self, i: usize) { let mut m = self.0.lock().unwrap(); m.items += i; m.print(m.files >= 1 || m.items >= 1); } } struct StatusPart<'a>(&'a StatusReport, usize); impl<'a> StatusPart<'a> { fn enter_item(&mut self, i: String) { self.0.enter_item(i); self.1 -= 1; } fn update_item(&mut self, i: String) { self.0.update_item(i); } fn changed_item(&mut self) { self.0.changed_item(); } } impl<'a> Drop for StatusPart<'a> { fn drop(&mut self) { self.0.skip_items(self.1); } }