prodash/progress/
utils.rs

1use crate::{messages::MessageLevel, progress::Id, Count, NestedProgress, Progress, Unit};
2use std::sync::atomic::AtomicUsize;
3use std::sync::Arc;
4
5/// An implementation of [`NestedProgress`] which discards all calls.
6pub struct Discard;
7
8impl Count for Discard {
9    fn set(&self, _step: usize) {}
10
11    fn step(&self) -> usize {
12        0
13    }
14
15    fn inc_by(&self, _step: usize) {}
16
17    fn counter(&self) -> StepShared {
18        Arc::new(AtomicUsize::default())
19    }
20}
21
22impl Progress for Discard {
23    fn init(&mut self, _max: Option<usize>, _unit: Option<Unit>) {}
24
25    fn set_max(&mut self, _max: Option<Step>) -> Option<Step> {
26        None
27    }
28    fn set_name(&mut self, _name: String) {}
29
30    fn name(&self) -> Option<String> {
31        None
32    }
33
34    fn id(&self) -> Id {
35        crate::progress::UNKNOWN
36    }
37
38    fn message(&self, _level: MessageLevel, _message: String) {}
39}
40
41impl NestedProgress for Discard {
42    type SubProgress = Self;
43
44    fn add_child(&mut self, _name: impl Into<String>) -> Self {
45        Discard
46    }
47
48    fn add_child_with_id(&mut self, _name: impl Into<String>, _id: Id) -> Self {
49        Discard
50    }
51}
52
53/// An implementation of [`NestedProgress`] showing either one or the other implementation.
54///
55/// Useful in conjunction with [`Discard`] and a working implementation, making it as a form of `Option<Progress>` which
56/// can be passed to methods requiring `impl Progress`.
57/// See [`DoOrDiscard`] for an incarnation of this.
58#[allow(missing_docs)]
59pub enum Either<L, R> {
60    Left(L),
61    Right(R),
62}
63
64impl<L, R> Count for Either<L, R>
65where
66    L: Count,
67    R: Count,
68{
69    fn set(&self, step: usize) {
70        match self {
71            Either::Left(l) => l.set(step),
72            Either::Right(r) => r.set(step),
73        }
74    }
75    fn step(&self) -> usize {
76        match self {
77            Either::Left(l) => l.step(),
78            Either::Right(r) => r.step(),
79        }
80    }
81    fn inc_by(&self, step: usize) {
82        match self {
83            Either::Left(l) => l.inc_by(step),
84            Either::Right(r) => r.inc_by(step),
85        }
86    }
87    fn counter(&self) -> StepShared {
88        match self {
89            Either::Left(l) => l.counter(),
90            Either::Right(r) => r.counter(),
91        }
92    }
93}
94
95impl<L, R> Progress for Either<L, R>
96where
97    L: Progress,
98    R: Progress,
99{
100    fn init(&mut self, max: Option<usize>, unit: Option<Unit>) {
101        match self {
102            Either::Left(l) => l.init(max, unit),
103            Either::Right(r) => r.init(max, unit),
104        }
105    }
106
107    fn unit(&self) -> Option<Unit> {
108        match self {
109            Either::Left(l) => l.unit(),
110            Either::Right(r) => r.unit(),
111        }
112    }
113
114    fn max(&self) -> Option<usize> {
115        match self {
116            Either::Left(l) => l.max(),
117            Either::Right(r) => r.max(),
118        }
119    }
120
121    fn set_max(&mut self, max: Option<Step>) -> Option<Step> {
122        match self {
123            Either::Left(l) => l.set_max(max),
124            Either::Right(r) => r.set_max(max),
125        }
126    }
127
128    fn set_name(&mut self, name: String) {
129        match self {
130            Either::Left(l) => l.set_name(name),
131            Either::Right(r) => r.set_name(name),
132        }
133    }
134
135    fn name(&self) -> Option<String> {
136        match self {
137            Either::Left(l) => l.name(),
138            Either::Right(r) => r.name(),
139        }
140    }
141
142    fn id(&self) -> Id {
143        match self {
144            Either::Left(l) => l.id(),
145            Either::Right(r) => r.id(),
146        }
147    }
148
149    fn message(&self, level: MessageLevel, message: String) {
150        match self {
151            Either::Left(l) => l.message(level, message),
152            Either::Right(r) => r.message(level, message),
153        }
154    }
155}
156
157impl<L, R> NestedProgress for Either<L, R>
158where
159    L: NestedProgress,
160    R: NestedProgress,
161{
162    type SubProgress = Either<L::SubProgress, R::SubProgress>;
163
164    fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress {
165        match self {
166            Either::Left(l) => Either::Left(l.add_child(name)),
167            Either::Right(r) => Either::Right(r.add_child(name)),
168        }
169    }
170
171    fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Self::SubProgress {
172        match self {
173            Either::Left(l) => Either::Left(l.add_child_with_id(name, id)),
174            Either::Right(r) => Either::Right(r.add_child_with_id(name, id)),
175        }
176    }
177}
178
179/// An implementation of `Progress` which can be created easily from `Option<impl Progress>`.
180pub struct DoOrDiscard<T>(Either<T, Discard>);
181
182impl<T> From<Option<T>> for DoOrDiscard<T>
183where
184    T: NestedProgress,
185{
186    fn from(p: Option<T>) -> Self {
187        match p {
188            Some(p) => DoOrDiscard(Either::Left(p)),
189            None => DoOrDiscard(Either::Right(Discard)),
190        }
191    }
192}
193
194impl<T: NestedProgress> DoOrDiscard<T> {
195    /// Obtain either the original [`NestedProgress`] implementation or `None`.
196    pub fn into_inner(self) -> Option<T> {
197        match self {
198            DoOrDiscard(Either::Left(p)) => Some(p),
199            DoOrDiscard(Either::Right(_)) => None,
200        }
201    }
202
203    /// Take out the implementation of [`NestedProgress`] and replace it with [`Discard`].
204    pub fn take(&mut self) -> Option<T> {
205        let this = std::mem::replace(self, DoOrDiscard::from(None));
206        match this {
207            DoOrDiscard(Either::Left(p)) => Some(p),
208            DoOrDiscard(Either::Right(_)) => None,
209        }
210    }
211}
212
213impl<T> Count for DoOrDiscard<T>
214where
215    T: Count,
216{
217    fn set(&self, step: usize) {
218        self.0.set(step)
219    }
220    fn step(&self) -> usize {
221        self.0.step()
222    }
223
224    fn inc_by(&self, step: usize) {
225        self.0.inc_by(step)
226    }
227
228    fn counter(&self) -> StepShared {
229        self.0.counter()
230    }
231}
232
233impl<T> Progress for DoOrDiscard<T>
234where
235    T: Progress,
236{
237    fn init(&mut self, max: Option<usize>, unit: Option<Unit>) {
238        self.0.init(max, unit)
239    }
240
241    fn unit(&self) -> Option<Unit> {
242        self.0.unit()
243    }
244
245    fn max(&self) -> Option<usize> {
246        self.0.max()
247    }
248
249    fn set_max(&mut self, max: Option<Step>) -> Option<Step> {
250        self.0.set_max(max)
251    }
252
253    fn set_name(&mut self, name: String) {
254        self.0.set_name(name);
255    }
256
257    fn name(&self) -> Option<String> {
258        self.0.name()
259    }
260
261    fn id(&self) -> Id {
262        self.0.id()
263    }
264
265    fn message(&self, level: MessageLevel, message: String) {
266        self.0.message(level, message)
267    }
268}
269
270impl<T> NestedProgress for DoOrDiscard<T>
271where
272    T: NestedProgress,
273{
274    type SubProgress = DoOrDiscard<T::SubProgress>;
275
276    fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress {
277        DoOrDiscard(self.0.add_child(name))
278    }
279
280    fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Self::SubProgress {
281        DoOrDiscard(self.0.add_child_with_id(name, id))
282    }
283}
284
285use std::time::Instant;
286
287use crate::progress::{Step, StepShared};
288
289/// Emit a message with throughput information when the instance is dropped.
290pub struct ThroughputOnDrop<T: NestedProgress>(T, Instant);
291
292impl<T: NestedProgress> ThroughputOnDrop<T> {
293    /// Create a new instance by providing the `inner` [`NestedProgress`] implementation.
294    pub fn new(inner: T) -> Self {
295        ThroughputOnDrop(inner, Instant::now())
296    }
297}
298
299impl<T: NestedProgress> Count for ThroughputOnDrop<T> {
300    fn set(&self, step: usize) {
301        self.0.set(step)
302    }
303
304    fn step(&self) -> usize {
305        self.0.step()
306    }
307
308    fn inc_by(&self, step: usize) {
309        self.0.inc_by(step)
310    }
311
312    fn counter(&self) -> StepShared {
313        self.0.counter()
314    }
315}
316
317impl<T: NestedProgress> Progress for ThroughputOnDrop<T> {
318    fn init(&mut self, max: Option<usize>, unit: Option<Unit>) {
319        self.0.init(max, unit)
320    }
321
322    fn unit(&self) -> Option<Unit> {
323        self.0.unit()
324    }
325
326    fn max(&self) -> Option<usize> {
327        self.0.max()
328    }
329
330    fn set_max(&mut self, max: Option<Step>) -> Option<Step> {
331        self.0.set_max(max)
332    }
333
334    fn set_name(&mut self, name: String) {
335        self.0.set_name(name)
336    }
337
338    fn name(&self) -> Option<String> {
339        self.0.name()
340    }
341
342    fn id(&self) -> Id {
343        self.0.id()
344    }
345
346    fn message(&self, level: MessageLevel, message: String) {
347        self.0.message(level, message)
348    }
349}
350
351impl<T: NestedProgress> NestedProgress for ThroughputOnDrop<T> {
352    type SubProgress = ThroughputOnDrop<T::SubProgress>;
353
354    fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress {
355        ThroughputOnDrop::new(self.0.add_child(name))
356    }
357
358    fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Self::SubProgress {
359        ThroughputOnDrop::new(self.0.add_child_with_id(name, id))
360    }
361}
362
363impl<T: NestedProgress> Drop for ThroughputOnDrop<T> {
364    fn drop(&mut self) {
365        self.0.show_throughput(self.1)
366    }
367}