| @@ -1,8 +1,21 @@ |
| | 1 | /// The severity of a message |
| | 2 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] |
| | 3 | pub enum MessageLevel { |
| | 4 | /// Rarely sent information related to the progress, not to be confused with the progress itself |
| | 5 | Info, |
| | 6 | /// Used to indicate that a task has failed, along with the reason |
| | 7 | Failure, |
| | 8 | /// Indicates a task was completed successfully |
| | 9 | Success, |
| | 10 | } |
| | 11 | |
| 1 | pub trait Progress { | 12 | pub trait Progress { |
| | 13 | type SubProgress: Progress; |
| | 14 | |
| 2 | /// Adds a new child, whose parent is this instance, with the given name. | 15 | /// Adds a new child, whose parent is this instance, with the given name. |
| 3 | /// | 16 | /// |
| 4 | /// This will make the child progress to appear contained in the parent progress. | 17 | /// This will make the child progress to appear contained in the parent progress. |
| 5 | fn add_child(&self, name: impl Into<String>) -> Self; | 18 | fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress; |
| 6 | | 19 | |
| 7 | /// Initialize the Item for receiving progress information. | 20 | /// Initialize the Item for receiving progress information. |
| 8 | /// | 21 | /// |
| @@ -19,15 +32,100 @@ pub trait Progress { · 10 unmodified lines |
| 19 | /// **Note** that this method can be called multiple times, changing the bounded-ness and unit at will. | 32 | /// **Note** that this method can be called multiple times, changing the bounded-ness and unit at will. |
| 20 | fn init(&mut self, max: Option<u32>, unit: Option<&'static str>); | 33 | fn init(&mut self, max: Option<u32>, unit: Option<&'static str>); |
| 21 | | 34 | |
| 22 | /// Set the current progress to the given `step`. | 35 | /// Set the current progress to the given `step`. The cost of this call is negligible, |
| | 36 | /// making manual throttling *not* necessary. |
| 23 | /// | 37 | /// |
| 24 | /// **Note**: that this call has no effect unless `init(…)` was called before. | 38 | /// **Note**: that this call has no effect unless `init(…)` was called before. |
| 25 | fn set(&mut self, step: u32); | 39 | fn set(&mut self, step: u32); |
| 26 | | 40 | |
| | 41 | /// Create a `message` of the given `level` and store it with the progress tree. |
| | 42 | /// |
| | 43 | /// Use this to provide additional,human-readable information about the progress |
| | 44 | /// made, including indicating success or failure. |
| | 45 | fn message(&self, level: MessageLevel, message: impl Into<String>); |
| | 46 | |
| 27 | /// Create a message providing additional information about the progress thus far. | 47 | /// Create a message providing additional information about the progress thus far. |
| 28 | fn info(&self, name: impl Into<String>) -> Self; | 48 | fn info(&self, message: impl Into<String>) { |
| | 49 | self.message(MessageLevel::Info, message) |
| | 50 | } |
| 29 | /// Create a message indicating the task is done successfully | 51 | /// Create a message indicating the task is done successfully |
| 30 | fn done(&self, name: impl Into<String>) -> Self; | 52 | fn done(&self, message: impl Into<String>) { |
| | 53 | self.message(MessageLevel::Success, message) |
| | 54 | } |
| 31 | /// Create a message indicating the task failed | 55 | /// Create a message indicating the task failed |
| 32 | fn fail(&self, name: impl Into<String>) -> Self; | 56 | fn fail(&self, message: impl Into<String>) { |
| | 57 | self.message(MessageLevel::Failure, message) |
| | 58 | } |
| | 59 | } |
| | 60 | |
| | 61 | #[cfg(feature = "progress-log")] |
| | 62 | mod log { |
| | 63 | use crate::progress::{MessageLevel, Progress}; |
| | 64 | use std::time::Duration; |
| | 65 | |
| | 66 | pub struct LogProgress { |
| | 67 | name: String, |
| | 68 | max: Option<u32>, |
| | 69 | unit: Option<&'static str>, |
| | 70 | last_set: Option<std::time::SystemTime>, |
| | 71 | } |
| | 72 | |
| | 73 | const EMIT_LOG_EVERY_S: f32 = 0.5; |
| | 74 | |
| | 75 | impl LogProgress { |
| | 76 | pub fn new(name: impl Into<String>) -> Self { |
| | 77 | LogProgress { |
| | 78 | name: name.into(), |
| | 79 | max: None, |
| | 80 | unit: None, |
| | 81 | last_set: None, |
| | 82 | } |
| | 83 | } |
| | 84 | } |
| | 85 | |
| | 86 | impl Progress for LogProgress { |
| | 87 | type SubProgress = LogProgress; |
| | 88 | |
| | 89 | fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress { |
| | 90 | LogProgress::new(format!("{}::{}", self.name, Into::<String>::into(name))) |
| | 91 | } |
| | 92 | |
| | 93 | fn init(&mut self, max: Option<u32>, unit: Option<&'static str>) { |
| | 94 | self.max = max; |
| | 95 | self.unit = unit; |
| | 96 | } |
| | 97 | |
| | 98 | fn set(&mut self, step: u32) { |
| | 99 | let now = std::time::SystemTime::now(); |
| | 100 | let last = self.last_set.unwrap_or(now); |
| | 101 | if now |
| | 102 | .duration_since(last) |
| | 103 | .unwrap_or_else(|_| Duration::default()) |
| | 104 | .as_secs_f32() |
| | 105 | > EMIT_LOG_EVERY_S |
| | 106 | { |
| | 107 | match (self.max, self.unit) { |
| | 108 | (Some(max), Some(unit)) => { |
| | 109 | log::info!("{} → {} / {} {}", self.name, step, max, unit) |
| | 110 | } |
| | 111 | (None, Some(unit)) => log::info!("{} → {} {}", self.name, step, unit), |
| | 112 | (Some(max), None) => log::info!("{} → {} / {}", self.name, step, max), |
| | 113 | (None, None) => log::info!("{} → {}", self.name, step), |
| | 114 | } |
| | 115 | } |
| | 116 | self.last_set = Some(now); |
| | 117 | } |
| | 118 | |
| | 119 | fn message(&self, level: MessageLevel, message: impl Into<String>) { |
| | 120 | let message: String = message.into(); |
| | 121 | match level { |
| | 122 | MessageLevel::Info => log::info!("ℹ{} → {}", self.name, message), |
| | 123 | MessageLevel::Failure => log::error!("𐄂{} → {}", self.name, message), |
| | 124 | MessageLevel::Success => log::info!("✓{} → {}", self.name, message), |
| | 125 | } |
| | 126 | } |
| | 127 | } |
| 33 | } | 128 | } |
| | 129 | |
| | 130 | #[cfg(feature = "progress-log")] |
| | 131 | pub use self::log::LogProgress; |