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