prodash/
traits.rs

1use std::time::Instant;
2
3use crate::{messages::MessageLevel, progress, progress::Id, Unit};
4
5/// A trait for describing hierarchical progress.
6pub trait NestedProgress: Progress {
7    /// The type of progress returned by [`add_child()`][Progress::add_child()].
8    type SubProgress: NestedProgress;
9
10    /// Adds a new child, whose parent is this instance, with the given `name`.
11    ///
12    /// This will make the child progress to appear contained in the parent progress.
13    /// Note that such progress does not have a stable identifier, which can be added
14    /// with [`add_child_with_id()`][Progress::add_child_with_id()] if desired.
15    fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress;
16
17    /// Adds a new child, whose parent is this instance, with the given `name` and `id`.
18    ///
19    /// This will make the child progress to appear contained in the parent progress, and it can be identified
20    /// using `id`.
21    fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Self::SubProgress;
22}
23
24/// A thread-safe read-only counter, with unknown limits.
25pub trait Count {
26    /// Set the current progress to the given `step`. The cost of this call is negligible,
27    /// making manual throttling *not* necessary.
28    ///
29    /// **Note**: that this call has no effect unless `init(…)` was called before.
30    fn set(&self, step: progress::Step);
31
32    /// Returns the current step, as controlled by `inc*(…)` calls
33    fn step(&self) -> progress::Step;
34
35    /// Increment the current progress to the given `step`.
36    /// The cost of this call is negligible, making manual throttling *not* necessary.
37    fn inc_by(&self, step: progress::Step);
38
39    /// Increment the current progress to the given 1. The cost of this call is negligible,
40    /// making manual throttling *not* necessary.
41    fn inc(&self) {
42        self.inc_by(1)
43    }
44
45    /// Return an atomic counter for direct access to the underlying state.
46    ///
47    /// This is useful if multiple threads want to access the same progress, without the need
48    /// for provide each their own progress and aggregating the result.
49    fn counter(&self) -> StepShared;
50}
51
52/// An object-safe trait for describing hierarchical progress.
53///
54/// This will be automatically implemented for any type that implements
55/// [`NestedProgress`].
56pub trait DynNestedProgress: Progress + impls::Sealed {
57    /// See [`NestedProgress::add_child`]
58    fn add_child(&mut self, name: String) -> BoxedDynNestedProgress;
59
60    /// See [`NestedProgress::add_child_with_id`]
61    fn add_child_with_id(&mut self, name: String, id: Id) -> BoxedDynNestedProgress;
62}
63
64/// An opaque type for storing [`DynNestedProgress`].
65pub struct BoxedDynNestedProgress(Box<dyn DynNestedProgress>);
66
67/// An owned version of [`Progress`] which can itself implement said trait.
68pub type BoxedProgress = Box<dyn Progress>;
69
70/// A bridge type that implements [`NestedProgress`] for any type that implements [`DynNestedProgress`].
71pub struct DynNestedProgressToNestedProgress<T: ?Sized>(pub T);
72
73/// A trait for describing non-hierarchical progress.
74///
75/// It differs by not being able to add child progress dynamically, but in turn is object safe. It's recommended to
76/// use this trait whenever there is no need to add child progress, at the leaf of a computation.
77// NOTE: keep this in-sync with `Progress`.
78pub trait Progress: Count + Send + Sync {
79    /// Initialize the Item for receiving progress information.
80    ///
81    /// If `max` is `Some(…)`, it will be treated as upper bound. When progress is [set(…)](./struct.Item.html#method.set)
82    /// it should not exceed the given maximum.
83    /// If `max` is `None`, the progress is unbounded. Use this if the amount of work cannot accurately
84    /// be determined in advance.
85    ///
86    /// If `unit` is `Some(…)`, it is used for display purposes only. See `prodash::Unit` for more information.
87    ///
88    /// If both `unit` and `max` are `None`, the item will be reset to be equivalent to 'uninitialized'.
89    ///
90    /// If this method is never called, this `Progress` instance will serve as organizational unit, useful to add more structure
91    /// to the progress tree (e.g. a headline).
92    ///
93    /// **Note** that this method can be called multiple times, changing the bounded-ness and unit at will.
94    fn init(&mut self, max: Option<progress::Step>, unit: Option<Unit>);
95
96    /// Returns the (cloned) unit associated with this Progress
97    fn unit(&self) -> Option<Unit> {
98        None
99    }
100
101    /// Returns the maximum about of items we expect, as provided with the `init(…)` call
102    fn max(&self) -> Option<progress::Step> {
103        None
104    }
105
106    /// Set the maximum value to `max` and return the old maximum value.
107    fn set_max(&mut self, _max: Option<progress::Step>) -> Option<progress::Step> {
108        None
109    }
110
111    /// Set the name of the instance, altering the value given when crating it with `add_child(…)`
112    /// The progress is allowed to discard it.
113    fn set_name(&mut self, name: String);
114
115    /// Get the name of the instance as given when creating it with `add_child(…)`
116    /// The progress is allowed to not be named, thus there is no guarantee that a previously set names 'sticks'.
117    fn name(&self) -> Option<String>;
118
119    /// Get a stable identifier for the progress instance.
120    /// Note that it could be [unknown][crate::progress::UNKNOWN].
121    fn id(&self) -> Id;
122
123    /// Create a `message` of the given `level` and store it with the progress tree.
124    ///
125    /// Use this to provide additional,human-readable information about the progress
126    /// made, including indicating success or failure.
127    fn message(&self, level: MessageLevel, message: String);
128
129    /// Create a message providing additional information about the progress thus far.
130    fn info(&self, message: String) {
131        self.message(MessageLevel::Info, message)
132    }
133    /// Create a message indicating the task is done successfully
134    fn done(&self, message: String) {
135        self.message(MessageLevel::Success, message)
136    }
137    /// Create a message indicating the task failed
138    fn fail(&self, message: String) {
139        self.message(MessageLevel::Failure, message)
140    }
141    /// A shorthand to print throughput information
142    fn show_throughput(&self, start: Instant) {
143        let step = self.step();
144        match self.unit() {
145            Some(unit) => self.show_throughput_with(start, step, unit, MessageLevel::Info),
146            None => {
147                let elapsed = start.elapsed().as_secs_f32();
148                let steps_per_second = (step as f32 / elapsed) as progress::Step;
149                self.info(format!(
150                    "done {} items in {:.02}s ({} items/s)",
151                    step, elapsed, steps_per_second
152                ))
153            }
154        };
155    }
156
157    /// A shorthand to print throughput information, with the given step and unit, and message level.
158    fn show_throughput_with(&self, start: Instant, step: progress::Step, unit: Unit, level: MessageLevel) {
159        use std::fmt::Write;
160        let elapsed = start.elapsed().as_secs_f32();
161        let steps_per_second = (step as f32 / elapsed) as progress::Step;
162        let mut buf = String::with_capacity(128);
163        let unit = unit.as_display_value();
164        let push_unit = |buf: &mut String| {
165            buf.push(' ');
166            let len_before_unit = buf.len();
167            unit.display_unit(buf, step).ok();
168            if buf.len() == len_before_unit {
169                buf.pop();
170            }
171        };
172
173        buf.push_str("done ");
174        unit.display_current_value(&mut buf, step, None).ok();
175        push_unit(&mut buf);
176
177        buf.write_fmt(format_args!(" in {:.02}s (", elapsed)).ok();
178        unit.display_current_value(&mut buf, steps_per_second, None).ok();
179        push_unit(&mut buf);
180        buf.push_str("/s)");
181
182        self.message(level, buf);
183    }
184}
185
186use crate::{
187    messages::{Message, MessageCopyState},
188    progress::StepShared,
189};
190
191/// The top-level root as weak handle, which needs an upgrade to become a usable root.
192///
193/// If the underlying reference isn't present anymore, such upgrade will fail permanently.
194pub trait WeakRoot {
195    /// The type implementing the `Root` trait
196    type Root: Root;
197
198    /// Equivalent to `std::sync::Weak::upgrade()`.
199    fn upgrade(&self) -> Option<Self::Root>;
200}
201
202/// The top level of a progress task hierarchy, with `progress::Task`s identified with `progress::Key`s
203pub trait Root {
204    /// The type implementing the `WeakRoot` trait
205    type WeakRoot: WeakRoot;
206
207    /// Returns the maximum amount of messages we can keep before overwriting older ones.
208    fn messages_capacity(&self) -> usize;
209
210    /// Returns the current amount of tasks underneath the root, transitively.
211    /// **Note** that this is at most a guess as tasks can be added and removed in parallel.
212    fn num_tasks(&self) -> usize;
213
214    /// Copy the entire progress tree into the given `out` vector, so that
215    /// it can be traversed from beginning to end in order of hierarchy.
216    /// The `out` vec will be cleared automatically.
217    fn sorted_snapshot(&self, out: &mut Vec<(progress::Key, progress::Task)>);
218
219    /// Copy all messages from the internal ring buffer into the given `out`
220    /// vector. Messages are ordered from oldest to newest.
221    fn copy_messages(&self, out: &mut Vec<Message>);
222
223    /// Copy only new messages from the internal ring buffer into the given `out`
224    /// vector. Messages are ordered from oldest to newest.
225    fn copy_new_messages(&self, out: &mut Vec<Message>, prev: Option<MessageCopyState>) -> MessageCopyState;
226
227    /// Similar to `Arc::downgrade()`
228    fn downgrade(&self) -> Self::WeakRoot;
229}
230
231mod impls {
232    use std::{
233        ops::{Deref, DerefMut},
234        time::Instant,
235    };
236
237    use crate::traits::{BoxedProgress, Progress};
238    use crate::{
239        messages::MessageLevel,
240        progress::{Id, Step, StepShared},
241        BoxedDynNestedProgress, Count, DynNestedProgress, DynNestedProgressToNestedProgress, NestedProgress, Unit,
242    };
243
244    pub trait Sealed {}
245
246    impl<T> Count for &T
247    where
248        T: Count + ?Sized,
249    {
250        fn set(&self, step: Step) {
251            (*self).set(step)
252        }
253
254        fn step(&self) -> Step {
255            (*self).step()
256        }
257
258        fn inc_by(&self, step: Step) {
259            (*self).inc_by(step)
260        }
261
262        fn inc(&self) {
263            (*self).inc()
264        }
265
266        fn counter(&self) -> StepShared {
267            (*self).counter()
268        }
269    }
270
271    impl<T> Count for &mut T
272    where
273        T: Count + ?Sized,
274    {
275        fn set(&self, step: Step) {
276            self.deref().set(step)
277        }
278
279        fn step(&self) -> Step {
280            self.deref().step()
281        }
282
283        fn inc_by(&self, step: Step) {
284            self.deref().inc_by(step)
285        }
286
287        fn inc(&self) {
288            self.deref().inc()
289        }
290
291        fn counter(&self) -> StepShared {
292            self.deref().counter()
293        }
294    }
295
296    impl<T> Progress for &mut T
297    where
298        T: Progress + ?Sized,
299    {
300        fn init(&mut self, max: Option<Step>, unit: Option<Unit>) {
301            self.deref_mut().init(max, unit)
302        }
303
304        fn unit(&self) -> Option<Unit> {
305            self.deref().unit()
306        }
307
308        fn max(&self) -> Option<Step> {
309            self.deref().max()
310        }
311
312        fn set_max(&mut self, max: Option<Step>) -> Option<Step> {
313            self.deref_mut().set_max(max)
314        }
315
316        fn set_name(&mut self, name: String) {
317            self.deref_mut().set_name(name)
318        }
319
320        fn name(&self) -> Option<String> {
321            self.deref().name()
322        }
323
324        fn id(&self) -> Id {
325            self.deref().id()
326        }
327
328        fn message(&self, level: MessageLevel, message: String) {
329            self.deref().message(level, message)
330        }
331
332        fn info(&self, message: String) {
333            self.deref().info(message)
334        }
335
336        fn done(&self, message: String) {
337            self.deref().done(message)
338        }
339
340        fn fail(&self, message: String) {
341            self.deref().fail(message)
342        }
343
344        fn show_throughput(&self, start: Instant) {
345            self.deref().show_throughput(start)
346        }
347
348        fn show_throughput_with(&self, start: Instant, step: Step, unit: Unit, level: MessageLevel) {
349            self.deref().show_throughput_with(start, step, unit, level)
350        }
351    }
352
353    impl<T> NestedProgress for &mut T
354    where
355        T: NestedProgress + ?Sized,
356    {
357        type SubProgress = T::SubProgress;
358
359        fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress {
360            self.deref_mut().add_child(name)
361        }
362
363        fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Self::SubProgress {
364            self.deref_mut().add_child_with_id(name, id)
365        }
366    }
367
368    impl<T> Sealed for T where T: NestedProgress + ?Sized {}
369
370    impl<T, SubP> DynNestedProgress for T
371    where
372        T: NestedProgress<SubProgress = SubP> + ?Sized,
373        SubP: NestedProgress + 'static,
374    {
375        fn add_child(&mut self, name: String) -> BoxedDynNestedProgress {
376            BoxedDynNestedProgress::new(self.add_child(name))
377        }
378
379        fn add_child_with_id(&mut self, name: String, id: Id) -> BoxedDynNestedProgress {
380            BoxedDynNestedProgress::new(self.add_child_with_id(name, id))
381        }
382    }
383
384    impl BoxedDynNestedProgress {
385        /// Create new instance from a `DynProgress` implementation.
386        pub fn new(progress: impl DynNestedProgress + 'static) -> Self {
387            Self(Box::new(progress))
388        }
389    }
390
391    impl Progress for BoxedDynNestedProgress {
392        fn init(&mut self, max: Option<Step>, unit: Option<Unit>) {
393            self.0.init(max, unit)
394        }
395
396        fn unit(&self) -> Option<Unit> {
397            self.0.unit()
398        }
399
400        fn max(&self) -> Option<Step> {
401            self.0.max()
402        }
403
404        fn set_max(&mut self, max: Option<Step>) -> Option<Step> {
405            self.0.set_max(max)
406        }
407
408        fn set_name(&mut self, name: String) {
409            self.0.set_name(name)
410        }
411
412        fn name(&self) -> Option<String> {
413            self.0.name()
414        }
415
416        fn id(&self) -> Id {
417            self.0.id()
418        }
419
420        fn message(&self, level: MessageLevel, message: String) {
421            self.0.message(level, message)
422        }
423
424        fn show_throughput(&self, start: Instant) {
425            self.0.show_throughput(start)
426        }
427
428        fn show_throughput_with(&self, start: Instant, step: Step, unit: Unit, level: MessageLevel) {
429            self.0.show_throughput_with(start, step, unit, level)
430        }
431    }
432
433    impl Progress for BoxedProgress {
434        fn init(&mut self, max: Option<Step>, unit: Option<Unit>) {
435            self.deref_mut().init(max, unit)
436        }
437
438        fn unit(&self) -> Option<Unit> {
439            self.deref().unit()
440        }
441
442        fn max(&self) -> Option<Step> {
443            self.deref().max()
444        }
445
446        fn set_max(&mut self, max: Option<Step>) -> Option<Step> {
447            self.deref_mut().set_max(max)
448        }
449
450        fn set_name(&mut self, name: String) {
451            self.deref_mut().set_name(name)
452        }
453
454        fn name(&self) -> Option<String> {
455            self.deref().name()
456        }
457
458        fn id(&self) -> Id {
459            self.deref().id()
460        }
461
462        fn message(&self, level: MessageLevel, message: String) {
463            self.deref().message(level, message)
464        }
465
466        fn show_throughput(&self, start: Instant) {
467            self.deref().show_throughput(start)
468        }
469
470        fn show_throughput_with(&self, start: Instant, step: Step, unit: Unit, level: MessageLevel) {
471            self.deref().show_throughput_with(start, step, unit, level)
472        }
473    }
474
475    impl Count for BoxedDynNestedProgress {
476        fn set(&self, step: Step) {
477            self.0.set(step)
478        }
479
480        fn step(&self) -> Step {
481            self.0.step()
482        }
483
484        fn inc_by(&self, step: Step) {
485            self.0.inc_by(step)
486        }
487
488        fn inc(&self) {
489            self.0.inc()
490        }
491
492        fn counter(&self) -> StepShared {
493            self.0.counter()
494        }
495    }
496
497    impl Count for BoxedProgress {
498        fn set(&self, step: Step) {
499            self.deref().set(step)
500        }
501
502        fn step(&self) -> Step {
503            self.deref().step()
504        }
505
506        fn inc_by(&self, step: Step) {
507            self.deref().inc_by(step)
508        }
509
510        fn inc(&self) {
511            self.deref().inc()
512        }
513
514        fn counter(&self) -> StepShared {
515            self.deref().counter()
516        }
517    }
518
519    impl NestedProgress for BoxedDynNestedProgress {
520        type SubProgress = Self;
521
522        fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress {
523            self.0.add_child(name.into())
524        }
525
526        fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Self::SubProgress {
527            self.0.add_child_with_id(name.into(), id)
528        }
529    }
530
531    impl<T> Progress for DynNestedProgressToNestedProgress<T>
532    where
533        T: ?Sized + Progress,
534    {
535        fn init(&mut self, max: Option<Step>, unit: Option<Unit>) {
536            self.0.init(max, unit)
537        }
538
539        fn unit(&self) -> Option<Unit> {
540            self.0.unit()
541        }
542
543        fn max(&self) -> Option<Step> {
544            self.0.max()
545        }
546
547        fn set_max(&mut self, max: Option<Step>) -> Option<Step> {
548            self.0.set_max(max)
549        }
550
551        fn set_name(&mut self, name: String) {
552            self.0.set_name(name)
553        }
554
555        fn name(&self) -> Option<String> {
556            self.0.name()
557        }
558
559        fn id(&self) -> Id {
560            self.0.id()
561        }
562
563        fn message(&self, level: MessageLevel, message: String) {
564            self.0.message(level, message)
565        }
566
567        fn show_throughput(&self, start: Instant) {
568            self.0.show_throughput(start)
569        }
570
571        fn show_throughput_with(&self, start: Instant, step: Step, unit: Unit, level: MessageLevel) {
572            self.0.show_throughput_with(start, step, unit, level)
573        }
574    }
575
576    impl<T> Count for DynNestedProgressToNestedProgress<T>
577    where
578        T: ?Sized + Count,
579    {
580        fn set(&self, step: Step) {
581            self.0.set(step)
582        }
583
584        fn step(&self) -> Step {
585            self.0.step()
586        }
587
588        fn inc_by(&self, step: Step) {
589            self.0.inc_by(step)
590        }
591
592        fn inc(&self) {
593            self.0.inc()
594        }
595
596        fn counter(&self) -> StepShared {
597            self.0.counter()
598        }
599    }
600
601    impl<T> NestedProgress for DynNestedProgressToNestedProgress<T>
602    where
603        T: DynNestedProgress + ?Sized,
604    {
605        type SubProgress = BoxedDynNestedProgress;
606
607        fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress {
608            self.0.add_child(name.into())
609        }
610
611        fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Self::SubProgress {
612            self.0.add_child_with_id(name.into(), id)
613        }
614    }
615}