]> git.proxmox.com Git - rustc.git/blob - vendor/prodash/src/tree/item.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / prodash / src / tree / item.rs
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 fn drop(&mut self) {
22 self.tree.remove(&self.key);
23 }
24 }
25
26 impl Debug for Item {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 f.debug_struct("Item")
29 .field("key", &self.key)
30 .field("value", &self.value)
31 .finish_non_exhaustive()
32 }
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 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 self.tree.get_mut(&self.key, |v| {
65 self.value.store(0, Ordering::SeqCst);
66 v.progress = (max.is_some() || unit.is_some()).then(|| Value {
67 done_at: max,
68 unit,
69 step: Arc::clone(&self.value),
70 ..Default::default()
71 });
72 });
73 }
74 }
75
76 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 self.tree.get_mut(&self.key, |v| {
91 v.progress.as_mut().map(f);
92 });
93 }
94 }
95
96 /// Set the name of this task's progress to the given `name`.
97 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 self.tree.get_mut(&self.key, |v| {
107 v.name = name.into();
108 });
109 }
110 }
111
112 /// Get the name of this task's progress
113 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 self.tree.get(&self.key, |v| v.name.to_owned())
121 }
122 }
123
124 /// Get the stable identifier of this instance.
125 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 self.tree.get(&self.key, |v| v.id).unwrap_or(crate::progress::UNKNOWN)
136 }
137 }
138
139 /// Returns the current step, as controlled by `inc*(…)` calls
140 pub fn step(&self) -> Option<Step> {
141 self.value.load(Ordering::Relaxed).into()
142 }
143
144 /// Returns the maximum about of items we expect, as provided with the `init(…)` call
145 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 self.tree
155 .get(&self.key, |v| v.progress.as_ref().and_then(|p| p.done_at))
156 .flatten()
157 }
158 }
159
160 /// Set the maximum value to `max` and return the old maximum value.
161 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 self.tree
178 .get_mut(&self.key, |v| {
179 v.progress.as_mut().and_then(|p| {
180 let prev = p.done_at;
181 p.done_at = max;
182 prev
183 })
184 })
185 .flatten()
186 }
187 }
188
189 /// Returns the (cloned) unit associated with this Progress
190 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 self.tree
200 .get(&self.key, |v| v.progress.as_ref().and_then(|p| p.unit.clone()))
201 .flatten()
202 }
203 }
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 pub fn set(&self, step: Step) {
209 self.value.store(step, Ordering::SeqCst);
210 }
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 pub fn inc_by(&self, step: Step) {
216 self.value.fetch_add(step, Ordering::Relaxed);
217 }
218
219 /// Increment the current progress by one.
220 ///
221 /// **Note**: that this call has no effect unless `init(…)` was called before.
222 pub fn inc(&self) {
223 self.value.fetch_add(1, Ordering::Relaxed);
224 }
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 pub fn blocked(&self, reason: &'static str, eta: Option<SystemTime>) {
235 self.alter_progress(|p| p.state = State::Blocked(reason, eta));
236 }
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 pub fn halted(&self, reason: &'static str, eta: Option<SystemTime>) {
247 self.alter_progress(|p| p.state = State::Halted(reason, eta));
248 }
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 pub fn running(&self) {
253 self.alter_progress(|p| p.state = State::Running);
254 }
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 pub fn add_child(&mut self, name: impl Into<String>) -> Item {
262 self.add_child_with_id(name, crate::progress::UNKNOWN)
263 }
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 pub fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Item {
271 let child_key = self.key.add_child(self.highest_child_id);
272 let task = Task {
273 name: name.into(),
274 id,
275 progress: None,
276 };
277 #[cfg(feature = "progress-tree-hp-hashmap")]
278 self.tree.insert(child_key, task);
279 #[cfg(not(feature = "progress-tree-hp-hashmap"))]
280 self.tree.insert(child_key, task);
281 self.highest_child_id = self.highest_child_id.wrapping_add(1);
282 Item {
283 highest_child_id: 0,
284 value: Default::default(),
285 key: child_key,
286 tree: Arc::clone(&self.tree),
287 messages: Arc::clone(&self.messages),
288 }
289 }
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 pub fn message(&self, level: MessageLevel, message: impl Into<String>) {
296 let message: String = message.into();
297 self.messages.lock().push_overwrite(
298 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 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 name
317 },
318 message,
319 )
320 }
321
322 /// Create a message indicating the task is done
323 pub fn done(&mut self, message: impl Into<String>) {
324 self.message(MessageLevel::Success, message)
325 }
326
327 /// Create a message indicating the task failed
328 pub fn fail(&mut self, message: impl Into<String>) {
329 self.message(MessageLevel::Failure, message)
330 }
331
332 /// Create a message providing additional information about the progress thus far.
333 pub fn info(&mut self, message: impl Into<String>) {
334 self.message(MessageLevel::Info, message)
335 }
336
337 pub(crate) fn deep_clone(&self) -> Item {
338 Item {
339 key: self.key,
340 value: Arc::new(AtomicUsize::new(self.value.load(Ordering::SeqCst))),
341 highest_child_id: self.highest_child_id,
342 tree: Arc::new(self.tree.deref().clone()),
343 messages: Arc::new(Mutex::new(self.messages.lock().clone())),
344 }
345 }
346 }
347
348 impl crate::Count for Item {
349 fn set(&self, step: usize) {
350 Item::set(self, step)
351 }
352
353 fn step(&self) -> usize {
354 Item::step(self).unwrap_or(0)
355 }
356
357 fn inc_by(&self, step: usize) {
358 self.inc_by(step)
359 }
360
361 fn counter(&self) -> StepShared {
362 Arc::clone(&self.value)
363 }
364 }
365
366 impl crate::Progress for Item {
367 fn init(&mut self, max: Option<Step>, unit: Option<Unit>) {
368 Item::init(self, max, unit)
369 }
370
371 fn unit(&self) -> Option<Unit> {
372 Item::unit(self)
373 }
374
375 fn max(&self) -> Option<usize> {
376 Item::max(self)
377 }
378
379 fn set_max(&mut self, max: Option<Step>) -> Option<Step> {
380 Item::set_max(self, max)
381 }
382
383 fn set_name(&mut self, name: String) {
384 Item::set_name(self, name)
385 }
386
387 fn name(&self) -> Option<String> {
388 Item::name(self)
389 }
390
391 fn id(&self) -> Id {
392 Item::id(self)
393 }
394
395 fn message(&self, level: MessageLevel, message: String) {
396 Item::message(self, level, message)
397 }
398 }
399
400 impl crate::NestedProgress for Item {
401 type SubProgress = Item;
402
403 fn add_child(&mut self, name: impl Into<String>) -> Self {
404 Item::add_child(self, name)
405 }
406
407 fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Self {
408 Item::add_child_with_id(self, name, id)
409 }
410 }