5 atomic
::{AtomicUsize, Ordering}
,
11 use parking_lot
::Mutex
;
14 messages
::MessageLevel
,
15 progress
::{Id, State, Step, StepShared, Task, Value}
,
22 self.tree
.remove(&self.key
);
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()
36 /// Initialize the Item for receiving progress information.
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
43 /// If `unit` is `Some(…)`, it is used for display purposes only. It should be using the plural.
45 /// If this method is never called, this `Item` will serve as organizational unit, useful to add more structure
46 /// to the progress tree.
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")]
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
{
57 step
: Arc
::clone(&self.value
),
62 #[cfg(not(feature = "progress-tree-hp-hashmap"))]
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
{
69 step
: Arc
::clone(&self.value
),
76 fn alter_progress(&self, f
: impl FnMut(&mut Value
)) {
77 #[cfg(feature = "progress-tree-hp-hashmap")]
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
85 r
.value_mut().progress
.as_mut().map(f
);
88 #[cfg(not(feature = "progress-tree-hp-hashmap"))]
90 self.tree
.get_mut(&self.key
, |v
| {
91 v
.progress
.as_mut().map(f
);
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")]
100 if let Some(mut r
) = self.tree
.get_mut(&self.key
) {
101 r
.value_mut().name
= name
.into();
104 #[cfg(not(feature = "progress-tree-hp-hashmap"))]
106 self.tree
.get_mut(&self.key
, |v
| {
107 v
.name
= name
.into();
112 /// Get the name of this task's progress
113 pub fn name(&self) -> Option
<String
> {
114 #[cfg(feature = "progress-tree-hp-hashmap")]
116 self.tree
.get(&self.key
).map(|r
| r
.value().name
.to_owned())
118 #[cfg(not(feature = "progress-tree-hp-hashmap"))]
120 self.tree
.get(&self.key
, |v
| v
.name
.to_owned())
124 /// Get the stable identifier of this instance.
125 pub fn id(&self) -> Id
{
126 #[cfg(feature = "progress-tree-hp-hashmap")]
130 .map(|r
| r
.value().id
)
131 .unwrap_or(crate::progress
::UNKNOWN
)
133 #[cfg(not(feature = "progress-tree-hp-hashmap"))]
135 self.tree
.get(&self.key
, |v
| v
.id
).unwrap_or(crate::progress
::UNKNOWN
)
139 /// Returns the current step, as controlled by `inc*(…)` calls
140 pub fn step(&self) -> Option
<Step
> {
141 self.value
.load(Ordering
::Relaxed
).into()
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")]
150 .and_then(|r
| r
.value().progress
.as_ref().and_then(|p
| p
.done_at
))
152 #[cfg(not(feature = "progress-tree-hp-hashmap"))]
155 .get(&self.key
, |v
| v
.progress
.as_ref().and_then(|p
| p
.done_at
))
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")]
170 let prev
= p
.done_at
;
175 #[cfg(not(feature = "progress-tree-hp-hashmap"))]
178 .get_mut(&self.key
, |v
| {
179 v
.progress
.as_mut().and_then(|p
| {
180 let prev
= p
.done_at
;
189 /// Returns the (cloned) unit associated with this Progress
190 pub fn unit(&self) -> Option
<Unit
> {
191 #[cfg(feature = "progress-tree-hp-hashmap")]
195 .and_then(|r
| r
.value().progress
.as_ref().and_then(|p
| p
.unit
.clone()))
197 #[cfg(not(feature = "progress-tree-hp-hashmap"))]
200 .get(&self.key
, |v
| v
.progress
.as_ref().and_then(|p
| p
.unit
.clone()))
205 /// Set the current progress to the given `step`.
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
);
212 /// Increment the current progress by the given `step`.
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
);
219 /// Increment the current progress by one.
221 /// **Note**: that this call has no effect unless `init(…)` was called before.
223 self.value
.fetch_add(1, Ordering
::Relaxed
);
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.
230 /// If `eta` is `Some(…)`, it specifies the time at which this task is expected to
231 /// make progress again.
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
));
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.
242 /// If `eta` is `Some(…)`, it specifies the time at which this task is expected to
243 /// make progress again.
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
));
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
);
256 /// Adds a new child `Tree`, whose parent is this instance, with the given `name`.
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
261 pub fn add_child(&mut self, name
: impl Into
<String
>) -> Item
{
262 self.add_child_with_id(name
, crate::progress
::UNKNOWN
)
265 /// Adds a new child `Tree`, whose parent is this instance, with the given `name` and `id`.
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
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
);
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);
284 value
: Default
::default(),
286 tree
: Arc
::clone(&self.tree
),
287 messages
: Arc
::clone(&self.messages
),
291 /// Create a `message` of the given `level` and store it with the progress tree.
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(
301 #[cfg(feature = "progress-tree-hp-hashmap")]
303 name
= self.tree
.get(&self.key
).map(|v
| v
.name
.to_owned()).unwrap_or_default();
305 #[cfg(not(feature = "progress-tree-hp-hashmap"))]
307 name
= self.tree
.get(&self.key
, |v
| v
.name
.to_owned()).unwrap_or_default()
310 #[cfg(feature = "progress-tree-log")]
312 MessageLevel
::Failure
=> crate::warn
!("{} → {}", name
, message
),
313 MessageLevel
::Info
| MessageLevel
::Success
=> crate::info
!("{} → {}", name
, message
),
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
)
327 /// Create a message indicating the task failed
328 pub fn fail(&mut self, message
: impl Into
<String
>) {
329 self.message(MessageLevel
::Failure
, message
)
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
)
337 pub(crate) fn deep_clone(&self) -> Item
{
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())),
348 impl crate::Count
for Item
{
349 fn set(&self, step
: usize) {
350 Item
::set(self, step
)
353 fn step(&self) -> usize {
354 Item
::step(self).unwrap_or(0)
357 fn inc_by(&self, step
: usize) {
361 fn counter(&self) -> StepShared
{
362 Arc
::clone(&self.value
)
366 impl crate::Progress
for Item
{
367 fn init(&mut self, max
: Option
<Step
>, unit
: Option
<Unit
>) {
368 Item
::init(self, max
, unit
)
371 fn unit(&self) -> Option
<Unit
> {
375 fn max(&self) -> Option
<usize> {
379 fn set_max(&mut self, max
: Option
<Step
>) -> Option
<Step
> {
380 Item
::set_max(self, max
)
383 fn set_name(&mut self, name
: String
) {
384 Item
::set_name(self, name
)
387 fn name(&self) -> Option
<String
> {
395 fn message(&self, level
: MessageLevel
, message
: String
) {
396 Item
::message(self, level
, message
)
400 impl crate::NestedProgress
for Item
{
401 type SubProgress
= Item
;
403 fn add_child(&mut self, name
: impl Into
<String
>) -> Self {
404 Item
::add_child(self, name
)
407 fn add_child_with_id(&mut self, name
: impl Into
<String
>, id
: Id
) -> Self {
408 Item
::add_child_with_id(self, name
, id
)