use crate::{messages::MessageLevel, progress::Id, Count, NestedProgress, Progress, Unit}; use std::sync::atomic::AtomicUsize; use std::sync::Arc; /// An implementation of [`NestedProgress`] which discards all calls. pub struct Discard; impl Count for Discard { fn set(&self, _step: usize) {} fn step(&self) -> usize { 0 } fn inc_by(&self, _step: usize) {} fn counter(&self) -> StepShared { Arc::new(AtomicUsize::default()) } } impl Progress for Discard { fn init(&mut self, _max: Option, _unit: Option) {} fn set_max(&mut self, _max: Option) -> Option { None } fn set_name(&mut self, _name: String) {} fn name(&self) -> Option { None } fn id(&self) -> Id { crate::progress::UNKNOWN } fn message(&self, _level: MessageLevel, _message: String) {} } impl NestedProgress for Discard { type SubProgress = Self; fn add_child(&mut self, _name: impl Into) -> Self { Discard } fn add_child_with_id(&mut self, _name: impl Into, _id: Id) -> Self { Discard } } /// An implementation of [`NestedProgress`] showing either one or the other implementation. /// /// Useful in conjunction with [`Discard`] and a working implementation, making it as a form of `Option` which /// can be passed to methods requiring `impl Progress`. /// See [`DoOrDiscard`] for an incarnation of this. #[allow(missing_docs)] pub enum Either { Left(L), Right(R), } impl Count for Either where L: Count, R: Count, { fn set(&self, step: usize) { match self { Either::Left(l) => l.set(step), Either::Right(r) => r.set(step), } } fn step(&self) -> usize { match self { Either::Left(l) => l.step(), Either::Right(r) => r.step(), } } fn inc_by(&self, step: usize) { match self { Either::Left(l) => l.inc_by(step), Either::Right(r) => r.inc_by(step), } } fn counter(&self) -> StepShared { match self { Either::Left(l) => l.counter(), Either::Right(r) => r.counter(), } } } impl Progress for Either where L: Progress, R: Progress, { fn init(&mut self, max: Option, unit: Option) { match self { Either::Left(l) => l.init(max, unit), Either::Right(r) => r.init(max, unit), } } fn unit(&self) -> Option { match self { Either::Left(l) => l.unit(), Either::Right(r) => r.unit(), } } fn max(&self) -> Option { match self { Either::Left(l) => l.max(), Either::Right(r) => r.max(), } } fn set_max(&mut self, max: Option) -> Option { match self { Either::Left(l) => l.set_max(max), Either::Right(r) => r.set_max(max), } } fn set_name(&mut self, name: String) { match self { Either::Left(l) => l.set_name(name), Either::Right(r) => r.set_name(name), } } fn name(&self) -> Option { match self { Either::Left(l) => l.name(), Either::Right(r) => r.name(), } } fn id(&self) -> Id { match self { Either::Left(l) => l.id(), Either::Right(r) => r.id(), } } fn message(&self, level: MessageLevel, message: String) { match self { Either::Left(l) => l.message(level, message), Either::Right(r) => r.message(level, message), } } } impl NestedProgress for Either where L: NestedProgress, R: NestedProgress, { type SubProgress = Either; fn add_child(&mut self, name: impl Into) -> Self::SubProgress { match self { Either::Left(l) => Either::Left(l.add_child(name)), Either::Right(r) => Either::Right(r.add_child(name)), } } fn add_child_with_id(&mut self, name: impl Into, id: Id) -> Self::SubProgress { match self { Either::Left(l) => Either::Left(l.add_child_with_id(name, id)), Either::Right(r) => Either::Right(r.add_child_with_id(name, id)), } } } /// An implementation of `Progress` which can be created easily from `Option`. pub struct DoOrDiscard(Either); impl From> for DoOrDiscard where T: NestedProgress, { fn from(p: Option) -> Self { match p { Some(p) => DoOrDiscard(Either::Left(p)), None => DoOrDiscard(Either::Right(Discard)), } } } impl DoOrDiscard { /// Obtain either the original [`NestedProgress`] implementation or `None`. pub fn into_inner(self) -> Option { match self { DoOrDiscard(Either::Left(p)) => Some(p), DoOrDiscard(Either::Right(_)) => None, } } /// Take out the implementation of [`NestedProgress`] and replace it with [`Discard`]. pub fn take(&mut self) -> Option { let this = std::mem::replace(self, DoOrDiscard::from(None)); match this { DoOrDiscard(Either::Left(p)) => Some(p), DoOrDiscard(Either::Right(_)) => None, } } } impl Count for DoOrDiscard where T: Count, { fn set(&self, step: usize) { self.0.set(step) } fn step(&self) -> usize { self.0.step() } fn inc_by(&self, step: usize) { self.0.inc_by(step) } fn counter(&self) -> StepShared { self.0.counter() } } impl Progress for DoOrDiscard where T: Progress, { fn init(&mut self, max: Option, unit: Option) { self.0.init(max, unit) } fn unit(&self) -> Option { self.0.unit() } fn max(&self) -> Option { self.0.max() } fn set_max(&mut self, max: Option) -> Option { self.0.set_max(max) } fn set_name(&mut self, name: String) { self.0.set_name(name); } fn name(&self) -> Option { self.0.name() } fn id(&self) -> Id { self.0.id() } fn message(&self, level: MessageLevel, message: String) { self.0.message(level, message) } } impl NestedProgress for DoOrDiscard where T: NestedProgress, { type SubProgress = DoOrDiscard; fn add_child(&mut self, name: impl Into) -> Self::SubProgress { DoOrDiscard(self.0.add_child(name)) } fn add_child_with_id(&mut self, name: impl Into, id: Id) -> Self::SubProgress { DoOrDiscard(self.0.add_child_with_id(name, id)) } } use std::time::Instant; use crate::progress::{Step, StepShared}; /// Emit a message with throughput information when the instance is dropped. pub struct ThroughputOnDrop(T, Instant); impl ThroughputOnDrop { /// Create a new instance by providing the `inner` [`NestedProgress`] implementation. pub fn new(inner: T) -> Self { ThroughputOnDrop(inner, Instant::now()) } } impl Count for ThroughputOnDrop { fn set(&self, step: usize) { self.0.set(step) } fn step(&self) -> usize { self.0.step() } fn inc_by(&self, step: usize) { self.0.inc_by(step) } fn counter(&self) -> StepShared { self.0.counter() } } impl Progress for ThroughputOnDrop { fn init(&mut self, max: Option, unit: Option) { self.0.init(max, unit) } fn unit(&self) -> Option { self.0.unit() } fn max(&self) -> Option { self.0.max() } fn set_max(&mut self, max: Option) -> Option { self.0.set_max(max) } fn set_name(&mut self, name: String) { self.0.set_name(name) } fn name(&self) -> Option { self.0.name() } fn id(&self) -> Id { self.0.id() } fn message(&self, level: MessageLevel, message: String) { self.0.message(level, message) } } impl NestedProgress for ThroughputOnDrop { type SubProgress = ThroughputOnDrop; fn add_child(&mut self, name: impl Into) -> Self::SubProgress { ThroughputOnDrop::new(self.0.add_child(name)) } fn add_child_with_id(&mut self, name: impl Into, id: Id) -> Self::SubProgress { ThroughputOnDrop::new(self.0.add_child_with_id(name, id)) } } impl Drop for ThroughputOnDrop { fn drop(&mut self) { self.0.show_throughput(self.1) } }