diff --git a/src/lib.rs b/src/lib.rs index e3eb604..e8c5466 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ pub mod messages; pub mod progress; mod traits; -pub use traits::{Progress, RawProgress, Root, WeakRoot}; +pub use traits::{BoxedDynProgress, DynProgress, Progress, RawProgress, Root, WeakRoot}; mod throughput; pub use crate::throughput::Throughput; diff --git a/src/traits.rs b/src/traits.rs index 1aac1d4..dea7ff1 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -154,6 +154,79 @@ pub trait Progress: Send + Sync { } } +/// An object-safe trait for describing hierarchical progress. +/// +/// This will be automatically implemented for any type that implements +/// [`Progress`]. +pub trait DynProgress: Send + Sync + impls::Sealed { + /// See [`Progress::add_child`] + fn add_child(&mut self, name: String) -> BoxedDynProgress<'_>; + + /// See [`Progress::add_child_with_id`] + fn add_child_with_id(&mut self, name: String, id: Id) -> BoxedDynProgress<'_>; + + /// See [`Progress::init`] + fn init(&mut self, max: Option, unit: Option); + + /// See [`Progress::set`] + fn set(&mut self, step: progress::Step); + + /// See [`Progress::unit`] + fn unit(&self) -> Option; + + /// See [`Progress::max`] + fn max(&self) -> Option; + + /// See [`Progress::set_max`] + fn set_max(&mut self, _max: Option) -> Option; + + /// See [`Progress::step`] + fn step(&self) -> progress::Step; + + /// See [`Progress::inc_by`] + fn inc_by(&mut self, step: progress::Step); + + /// See [`Progress::inc`] + fn inc(&mut self); + + /// See [`Progress::set_name`] + fn set_name(&mut self, name: String); + + /// See [`Progress::name`] + fn name(&self) -> Option; + + /// See [`Progress::id`] + fn id(&self) -> Id; + + /// See [`Progress::message`] + fn message(&self, level: MessageLevel, message: String); + + /// See [`Progress::counter`] + fn counter(&self) -> Option; + + /// See [`Progress::info`] + fn info(&self, message: String); + + /// See [`Progress::done`] + fn done(&self, message: String); + + /// See [`Progress::fail`] + fn fail(&self, message: String); + + /// See [`Progress::show_throughput`] + fn show_throughput(&self, start: Instant); + + /// See [`Progress::show_throughput_with`] + fn show_throughput_with(&self, start: Instant, step: progress::Step, unit: Unit, level: MessageLevel); +} + +//#[derive(Debug)] +//pub struct DynProgressWrapper(T); + +/// An opaque type so that `gix` can internally change its implementation details, +/// e.g. use an `Arc` instead of `Box`, or even inlining the progress. +pub struct BoxedDynProgress<'a>(Box); + /// A trait for describing non-hierarchical progress. /// /// It differs by not being able to add child progress dynamically, but in turn is object safe. It's recommended to @@ -345,13 +418,15 @@ mod impls { time::Instant, }; - use crate::traits::RawProgress; use crate::{ messages::MessageLevel, progress::{Id, Step, StepShared}, - Progress, Unit, + traits::RawProgress, + BoxedDynProgress, DynProgress, Progress, Unit, }; + pub trait Sealed {} + impl RawProgress for T where T: Progress, @@ -515,4 +590,95 @@ mod impls { self.deref().show_throughput_with(start, step, unit, level) } } + + impl Sealed for T where T: Progress + ?Sized {} + + impl DynProgress for T + where + T: Progress + ?Sized, + { + fn add_child(&mut self, name: String) -> BoxedDynProgress<'_> { + BoxedDynProgress::new(self.add_child(name)) + } + + fn add_child_with_id(&mut self, name: String, id: Id) -> BoxedDynProgress<'_> { + BoxedDynProgress::new(self.add_child_with_id(name, id)) + } + + fn init(&mut self, max: Option, unit: Option) { + self.init(max, unit) + } + + fn set(&mut self, step: Step) { + self.set(step) + } + + fn unit(&self) -> Option { + self.unit() + } + + fn max(&self) -> Option { + self.max() + } + + fn set_max(&mut self, max: Option) -> Option { + self.set_max(max) + } + + fn step(&self) -> Step { + self.step() + } + + fn inc_by(&mut self, step: Step) { + self.inc_by(step) + } + + fn inc(&mut self) { + self.inc() + } + + fn set_name(&mut self, name: String) { + self.set_name(name) + } + + fn name(&self) -> Option { + self.name() + } + + fn id(&self) -> Id { + self.id() + } + + fn message(&self, level: MessageLevel, message: String) { + self.message(level, message) + } + + fn counter(&self) -> Option { + self.counter() + } + + fn info(&self, message: String) { + self.info(message) + } + fn done(&self, message: String) { + self.done(message) + } + fn fail(&self, message: String) { + self.fail(message) + } + + fn show_throughput(&self, start: Instant) { + self.show_throughput(start) + } + fn show_throughput_with(&self, start: Instant, step: Step, unit: Unit, level: MessageLevel) { + self.show_throughput_with(start, step, unit, level) + } + } + + impl<'a> BoxedDynProgress<'a> { + /// Create new boxed dyn Progress + pub fn new(progress: impl DynProgress + 'a) -> Self { + Self(Box::new(progress)) + } + } }