/rust/registry/src/index.crates.io-1949cf8c6b5b557f/prodash-31.0.0/src/tree/item.rs
Line | Count | Source |
1 | | use std::{ |
2 | | fmt::Debug, |
3 | | ops::Deref, |
4 | | sync::{ |
5 | | atomic::{AtomicUsize, Ordering}, |
6 | | Arc, |
7 | | }, |
8 | | time::SystemTime, |
9 | | }; |
10 | | |
11 | | use parking_lot::Mutex; |
12 | | |
13 | | use crate::{ |
14 | | messages::MessageLevel, |
15 | | progress::{Id, State, Step, StepShared, Task, Value}, |
16 | | tree::Item, |
17 | | unit::Unit, |
18 | | }; |
19 | | |
20 | | impl Drop for Item { |
21 | 0 | fn drop(&mut self) { |
22 | 0 | self.tree.remove(&self.key); |
23 | 0 | } |
24 | | } |
25 | | |
26 | | impl Debug for Item { |
27 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
28 | 0 | f.debug_struct("Item") |
29 | 0 | .field("key", &self.key) |
30 | 0 | .field("value", &self.value) |
31 | 0 | .finish_non_exhaustive() |
32 | 0 | } |
33 | | } |
34 | | |
35 | | impl Item { |
36 | | /// Initialize the Item for receiving progress information. |
37 | | /// |
38 | | /// If `max` is `Some(…)`, it will be treated as upper bound. When progress is [set(…)](./struct.Item.html#method.set) |
39 | | /// it should not exceed the given maximum. |
40 | | /// If `max` is `None`, the progress is unbounded. Use this if the amount of work cannot accurately |
41 | | /// be determined. |
42 | | /// |
43 | | /// If `unit` is `Some(…)`, it is used for display purposes only. It should be using the plural. |
44 | | /// |
45 | | /// If this method is never called, this `Item` will serve as organizational unit, useful to add more structure |
46 | | /// to the progress tree. |
47 | | /// |
48 | | /// **Note** that this method can be called multiple times, changing the bounded-ness and unit at will. |
49 | 0 | pub fn init(&self, max: Option<usize>, unit: Option<Unit>) { |
50 | | #[cfg(feature = "progress-tree-hp-hashmap")] |
51 | | { |
52 | | if let Some(mut r) = self.tree.get_mut(&self.key) { |
53 | | self.value.store(0, Ordering::SeqCst); |
54 | | r.value_mut().progress = (max.is_some() || unit.is_some()).then(|| Value { |
55 | | done_at: max, |
56 | | unit, |
57 | | step: Arc::clone(&self.value), |
58 | | ..Default::default() |
59 | | }) |
60 | | }; |
61 | | } |
62 | | #[cfg(not(feature = "progress-tree-hp-hashmap"))] |
63 | | { |
64 | 0 | self.tree.get_mut(&self.key, |v| { |
65 | 0 | self.value.store(0, Ordering::SeqCst); |
66 | 0 | v.progress = (max.is_some() || unit.is_some()).then(|| Value { |
67 | 0 | done_at: max, |
68 | 0 | unit, |
69 | 0 | step: Arc::clone(&self.value), |
70 | 0 | ..Default::default() |
71 | 0 | }); |
72 | 0 | }); |
73 | | } |
74 | 0 | } |
75 | | |
76 | 0 | fn alter_progress(&self, f: impl FnMut(&mut Value)) { |
77 | | #[cfg(feature = "progress-tree-hp-hashmap")] |
78 | | { |
79 | | if let Some(mut r) = self.tree.get_mut(&self.key) { |
80 | | // NOTE: since we wrap around, if there are more tasks than we can have IDs for, |
81 | | // and if all these tasks are still alive, two progress trees may see the same ID |
82 | | // when these go out of scope, they delete the key and the other tree will not find |
83 | | // its value anymore. Besides, it's probably weird to see tasks changing their progress |
84 | | // all the time… |
85 | | r.value_mut().progress.as_mut().map(f); |
86 | | }; |
87 | | } |
88 | | #[cfg(not(feature = "progress-tree-hp-hashmap"))] |
89 | | { |
90 | 0 | self.tree.get_mut(&self.key, |v| { |
91 | 0 | v.progress.as_mut().map(f); |
92 | 0 | }); Unexecuted instantiation: <prodash::tree::Item>::alter_progress::<<prodash::tree::Item>::halted::{closure#0}>::{closure#0}Unexecuted instantiation: <prodash::tree::Item>::alter_progress::<<prodash::tree::Item>::blocked::{closure#0}>::{closure#0}Unexecuted instantiation: <prodash::tree::Item>::alter_progress::<<prodash::tree::Item>::running::{closure#0}>::{closure#0} |
93 | | } |
94 | 0 | } Unexecuted instantiation: <prodash::tree::Item>::alter_progress::<<prodash::tree::Item>::halted::{closure#0}>Unexecuted instantiation: <prodash::tree::Item>::alter_progress::<<prodash::tree::Item>::blocked::{closure#0}>Unexecuted instantiation: <prodash::tree::Item>::alter_progress::<<prodash::tree::Item>::running::{closure#0}> |
95 | | |
96 | | /// Set the name of this task's progress to the given `name`. |
97 | 0 | pub fn set_name(&self, name: impl Into<String>) { |
98 | | #[cfg(feature = "progress-tree-hp-hashmap")] |
99 | | { |
100 | | if let Some(mut r) = self.tree.get_mut(&self.key) { |
101 | | r.value_mut().name = name.into(); |
102 | | }; |
103 | | } |
104 | | #[cfg(not(feature = "progress-tree-hp-hashmap"))] |
105 | | { |
106 | 0 | self.tree.get_mut(&self.key, |v| { |
107 | 0 | v.name = name.into(); |
108 | 0 | }); |
109 | | } |
110 | 0 | } |
111 | | |
112 | | /// Get the name of this task's progress |
113 | 0 | pub fn name(&self) -> Option<String> { |
114 | | #[cfg(feature = "progress-tree-hp-hashmap")] |
115 | | { |
116 | | self.tree.get(&self.key).map(|r| r.value().name.to_owned()) |
117 | | } |
118 | | #[cfg(not(feature = "progress-tree-hp-hashmap"))] |
119 | | { |
120 | 0 | self.tree.get(&self.key, |v| v.name.to_owned()) |
121 | | } |
122 | 0 | } |
123 | | |
124 | | /// Get the stable identifier of this instance. |
125 | 0 | pub fn id(&self) -> Id { |
126 | | #[cfg(feature = "progress-tree-hp-hashmap")] |
127 | | { |
128 | | self.tree |
129 | | .get(&self.key) |
130 | | .map(|r| r.value().id) |
131 | | .unwrap_or(crate::progress::UNKNOWN) |
132 | | } |
133 | | #[cfg(not(feature = "progress-tree-hp-hashmap"))] |
134 | | { |
135 | 0 | self.tree.get(&self.key, |v| v.id).unwrap_or(crate::progress::UNKNOWN) |
136 | | } |
137 | 0 | } |
138 | | |
139 | | /// Returns the current step, as controlled by `inc*(…)` calls |
140 | 0 | pub fn step(&self) -> Option<Step> { |
141 | 0 | self.value.load(Ordering::Relaxed).into() |
142 | 0 | } |
143 | | |
144 | | /// Returns the maximum about of items we expect, as provided with the `init(…)` call |
145 | 0 | pub fn max(&self) -> Option<Step> { |
146 | | #[cfg(feature = "progress-tree-hp-hashmap")] |
147 | | { |
148 | | self.tree |
149 | | .get(&self.key) |
150 | | .and_then(|r| r.value().progress.as_ref().and_then(|p| p.done_at)) |
151 | | } |
152 | | #[cfg(not(feature = "progress-tree-hp-hashmap"))] |
153 | | { |
154 | 0 | self.tree |
155 | 0 | .get(&self.key, |v| v.progress.as_ref().and_then(|p| p.done_at)) |
156 | 0 | .flatten() |
157 | | } |
158 | 0 | } |
159 | | |
160 | | /// Set the maximum value to `max` and return the old maximum value. |
161 | 0 | pub fn set_max(&self, max: Option<Step>) -> Option<Step> { |
162 | | #[cfg(feature = "progress-tree-hp-hashmap")] |
163 | | { |
164 | | self.tree |
165 | | .get_mut(&self.key)? |
166 | | .value_mut() |
167 | | .progress |
168 | | .as_mut() |
169 | | .and_then(|p| { |
170 | | let prev = p.done_at; |
171 | | p.done_at = max; |
172 | | prev |
173 | | }) |
174 | | } |
175 | | #[cfg(not(feature = "progress-tree-hp-hashmap"))] |
176 | | { |
177 | 0 | self.tree |
178 | 0 | .get_mut(&self.key, |v| { |
179 | 0 | v.progress.as_mut().and_then(|p| { |
180 | 0 | let prev = p.done_at; |
181 | 0 | p.done_at = max; |
182 | 0 | prev |
183 | 0 | }) |
184 | 0 | }) |
185 | 0 | .flatten() |
186 | | } |
187 | 0 | } |
188 | | |
189 | | /// Returns the (cloned) unit associated with this Progress |
190 | 0 | pub fn unit(&self) -> Option<Unit> { |
191 | | #[cfg(feature = "progress-tree-hp-hashmap")] |
192 | | { |
193 | | self.tree |
194 | | .get(&self.key) |
195 | | .and_then(|r| r.value().progress.as_ref().and_then(|p| p.unit.clone())) |
196 | | } |
197 | | #[cfg(not(feature = "progress-tree-hp-hashmap"))] |
198 | | { |
199 | 0 | self.tree |
200 | 0 | .get(&self.key, |v| v.progress.as_ref().and_then(|p| p.unit.clone())) |
201 | 0 | .flatten() |
202 | | } |
203 | 0 | } |
204 | | |
205 | | /// Set the current progress to the given `step`. |
206 | | /// |
207 | | /// **Note**: that this call has no effect unless `init(…)` was called before. |
208 | 0 | pub fn set(&self, step: Step) { |
209 | 0 | self.value.store(step, Ordering::SeqCst); |
210 | 0 | } |
211 | | |
212 | | /// Increment the current progress by the given `step`. |
213 | | /// |
214 | | /// **Note**: that this call has no effect unless `init(…)` was called before. |
215 | 0 | pub fn inc_by(&self, step: Step) { |
216 | 0 | self.value.fetch_add(step, Ordering::Relaxed); |
217 | 0 | } |
218 | | |
219 | | /// Increment the current progress by one. |
220 | | /// |
221 | | /// **Note**: that this call has no effect unless `init(…)` was called before. |
222 | 0 | pub fn inc(&self) { |
223 | 0 | self.value.fetch_add(1, Ordering::Relaxed); |
224 | 0 | } |
225 | | |
226 | | /// Call to indicate that progress cannot be indicated, and that the task cannot be interrupted. |
227 | | /// Use this, as opposed to `halted(…)`, if a non-interruptable call is about to be made without support |
228 | | /// for any progress indication. |
229 | | /// |
230 | | /// If `eta` is `Some(…)`, it specifies the time at which this task is expected to |
231 | | /// make progress again. |
232 | | /// |
233 | | /// The halted-state is undone next time [`tree::Item::running(…)`][Item::running()] is called. |
234 | 0 | pub fn blocked(&self, reason: &'static str, eta: Option<SystemTime>) { |
235 | 0 | self.alter_progress(|p| p.state = State::Blocked(reason, eta)); |
236 | 0 | } |
237 | | |
238 | | /// Call to indicate that progress cannot be indicated, even though the task can be interrupted. |
239 | | /// Use this, as opposed to `blocked(…)`, if an interruptable call is about to be made without support |
240 | | /// for any progress indication. |
241 | | /// |
242 | | /// If `eta` is `Some(…)`, it specifies the time at which this task is expected to |
243 | | /// make progress again. |
244 | | /// |
245 | | /// The halted-state is undone next time [`tree::Item::running(…)`][Item::running()] is called. |
246 | 0 | pub fn halted(&self, reason: &'static str, eta: Option<SystemTime>) { |
247 | 0 | self.alter_progress(|p| p.state = State::Halted(reason, eta)); |
248 | 0 | } |
249 | | |
250 | | /// Call to indicate that progress is back in running state, which should be called after the reason for |
251 | | /// calling `blocked()` or `halted()` has passed. |
252 | 0 | pub fn running(&self) { |
253 | 0 | self.alter_progress(|p| p.state = State::Running); |
254 | 0 | } |
255 | | |
256 | | /// Adds a new child `Tree`, whose parent is this instance, with the given `name`. |
257 | | /// |
258 | | /// **Important**: The depth of the hierarchy is limited to [`tree::Key::max_level`](./struct.Key.html#method.max_level). |
259 | | /// Exceeding the level will be ignored, and new tasks will be added to this instance's |
260 | | /// level instead. |
261 | 0 | pub fn add_child(&mut self, name: impl Into<String>) -> Item { |
262 | 0 | self.add_child_with_id(name, crate::progress::UNKNOWN) |
263 | 0 | } |
264 | | |
265 | | /// Adds a new child `Tree`, whose parent is this instance, with the given `name` and `id`. |
266 | | /// |
267 | | /// **Important**: The depth of the hierarchy is limited to [`tree::Key::max_level`](./struct.Key.html#method.max_level). |
268 | | /// Exceeding the level will be ignored, and new tasks will be added to this instance's |
269 | | /// level instead. |
270 | 0 | pub fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Item { |
271 | 0 | let child_key = self.key.add_child(self.highest_child_id); |
272 | 0 | let task = Task { |
273 | 0 | name: name.into(), |
274 | 0 | id, |
275 | 0 | progress: None, |
276 | 0 | }; |
277 | | #[cfg(feature = "progress-tree-hp-hashmap")] |
278 | | self.tree.insert(child_key, task); |
279 | | #[cfg(not(feature = "progress-tree-hp-hashmap"))] |
280 | 0 | self.tree.insert(child_key, task); |
281 | 0 | self.highest_child_id = self.highest_child_id.wrapping_add(1); |
282 | 0 | Item { |
283 | 0 | highest_child_id: 0, |
284 | 0 | value: Default::default(), |
285 | 0 | key: child_key, |
286 | 0 | tree: Arc::clone(&self.tree), |
287 | 0 | messages: Arc::clone(&self.messages), |
288 | 0 | } |
289 | 0 | } |
290 | | |
291 | | /// Create a `message` of the given `level` and store it with the progress tree. |
292 | | /// |
293 | | /// Use this to provide additional,human-readable information about the progress |
294 | | /// made, including indicating success or failure. |
295 | 0 | pub fn message(&self, level: MessageLevel, message: impl Into<String>) { |
296 | 0 | let message: String = message.into(); |
297 | 0 | self.messages.lock().push_overwrite( |
298 | 0 | level, |
299 | | { |
300 | | let name; |
301 | | #[cfg(feature = "progress-tree-hp-hashmap")] |
302 | | { |
303 | | name = self.tree.get(&self.key).map(|v| v.name.to_owned()).unwrap_or_default(); |
304 | | } |
305 | | #[cfg(not(feature = "progress-tree-hp-hashmap"))] |
306 | | { |
307 | 0 | name = self.tree.get(&self.key, |v| v.name.to_owned()).unwrap_or_default() |
308 | | } |
309 | | |
310 | | #[cfg(feature = "progress-tree-log")] |
311 | | match level { |
312 | | MessageLevel::Failure => crate::warn!("{} → {}", name, message), |
313 | | MessageLevel::Info | MessageLevel::Success => crate::info!("{} → {}", name, message), |
314 | | }; |
315 | | |
316 | 0 | name |
317 | | }, |
318 | 0 | message, |
319 | | ) |
320 | 0 | } |
321 | | |
322 | | /// Create a message indicating the task is done |
323 | 0 | pub fn done(&mut self, message: impl Into<String>) { |
324 | 0 | self.message(MessageLevel::Success, message) |
325 | 0 | } |
326 | | |
327 | | /// Create a message indicating the task failed |
328 | 0 | pub fn fail(&mut self, message: impl Into<String>) { |
329 | 0 | self.message(MessageLevel::Failure, message) |
330 | 0 | } |
331 | | |
332 | | /// Create a message providing additional information about the progress thus far. |
333 | 0 | pub fn info(&mut self, message: impl Into<String>) { |
334 | 0 | self.message(MessageLevel::Info, message) |
335 | 0 | } |
336 | | |
337 | 0 | pub(crate) fn deep_clone(&self) -> Item { |
338 | 0 | Item { |
339 | 0 | key: self.key, |
340 | 0 | value: Arc::new(AtomicUsize::new(self.value.load(Ordering::SeqCst))), |
341 | 0 | highest_child_id: self.highest_child_id, |
342 | 0 | tree: Arc::new(self.tree.deref().clone()), |
343 | 0 | messages: Arc::new(Mutex::new(self.messages.lock().clone())), |
344 | 0 | } |
345 | 0 | } |
346 | | } |
347 | | |
348 | | impl crate::Count for Item { |
349 | 0 | fn set(&self, step: usize) { |
350 | 0 | Item::set(self, step) |
351 | 0 | } |
352 | | |
353 | 0 | fn step(&self) -> usize { |
354 | 0 | Item::step(self).unwrap_or(0) |
355 | 0 | } |
356 | | |
357 | 0 | fn inc_by(&self, step: usize) { |
358 | 0 | self.inc_by(step) |
359 | 0 | } |
360 | | |
361 | 0 | fn counter(&self) -> StepShared { |
362 | 0 | Arc::clone(&self.value) |
363 | 0 | } |
364 | | } |
365 | | |
366 | | impl crate::Progress for Item { |
367 | 0 | fn init(&mut self, max: Option<Step>, unit: Option<Unit>) { |
368 | 0 | Item::init(self, max, unit) |
369 | 0 | } |
370 | | |
371 | 0 | fn unit(&self) -> Option<Unit> { |
372 | 0 | Item::unit(self) |
373 | 0 | } |
374 | | |
375 | 0 | fn max(&self) -> Option<usize> { |
376 | 0 | Item::max(self) |
377 | 0 | } |
378 | | |
379 | 0 | fn set_max(&mut self, max: Option<Step>) -> Option<Step> { |
380 | 0 | Item::set_max(self, max) |
381 | 0 | } |
382 | | |
383 | 0 | fn set_name(&mut self, name: String) { |
384 | 0 | Item::set_name(self, name) |
385 | 0 | } |
386 | | |
387 | 0 | fn name(&self) -> Option<String> { |
388 | 0 | Item::name(self) |
389 | 0 | } |
390 | | |
391 | 0 | fn id(&self) -> Id { |
392 | 0 | Item::id(self) |
393 | 0 | } |
394 | | |
395 | 0 | fn message(&self, level: MessageLevel, message: String) { |
396 | 0 | Item::message(self, level, message) |
397 | 0 | } |
398 | | } |
399 | | |
400 | | impl crate::NestedProgress for Item { |
401 | | type SubProgress = Item; |
402 | | |
403 | 0 | fn add_child(&mut self, name: impl Into<String>) -> Self { |
404 | 0 | Item::add_child(self, name) |
405 | 0 | } |
406 | | |
407 | 0 | fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Self { |
408 | 0 | Item::add_child_with_id(self, name, id) |
409 | 0 | } |
410 | | } |