progress_monitor/monitor/
sub.rs1use std::{
2 borrow::Cow,
3 fmt::{Debug, Display},
4};
5
6use crate::{work::Work, CloseError};
7
8use super::{ProgressMonitor, ProgressMonitorDivision};
9
10#[derive(Debug)]
23pub struct ChildMonitor<'n, 'p, W: Work, P: ProgressMonitor<W>> {
24 name: Cow<'n, str>,
25 parent: &'p mut P,
27 parent_work: W,
29 sub_work: W,
31 sub_work_completed: W,
33 parent_work_submitted: W,
35 closed: Option<Result<(), CloseError>>,
36}
37
38impl<'n, 'p, W: Work, P: ProgressMonitor<W>> ChildMonitor<'n, 'p, W, P> {
39 pub fn new(name: Cow<'n, str>, parent: &'p mut P, parent_work: W, sub_work: W) -> Self {
40 Self {
41 name,
42 parent,
43 parent_work,
44 sub_work,
45 sub_work_completed: W::zero(),
46 parent_work_submitted: W::zero(),
47 closed: None,
48 }
49 }
50
51 pub fn name(&self) -> Cow<'n, str> {
52 self.name.clone()
53 }
54}
55
56impl<'n, 'p, W: Work, P: ProgressMonitor<W>> ProgressMonitor<W> for ChildMonitor<'n, 'p, W, P> {
57 fn worked<A: Into<W>>(&mut self, amount_of_work: A) {
58 let amount_of_work: W = amount_of_work.into();
59
60 let now: W = (self.sub_work_completed.clone() + amount_of_work.clone()).unwrap();
62 if now > self.sub_work {
63 tracing::warn!(
66 work = ?self.sub_work,
67 work_done = ?self.sub_work_completed,
68 new_work_done = ?amount_of_work,
69 would_become = ?now,
70 "Detected overshoot. Try to only submit work left open. Ignoring additional work."
71 );
72 self.sub_work_completed = self.sub_work.clone();
73 } else {
74 self.sub_work_completed = now;
75 }
76
77 let finished = self.sub_work_completed == self.sub_work;
78
79 if !finished {
81 let amount_of_work: W = W::min(&amount_of_work, &self.sub_work).clone();
84 let parent_worked: W = W::parent_work_done_when(
85 amount_of_work,
86 self.sub_work.clone(),
87 self.parent_work.clone(),
88 );
89 self.parent.worked(parent_worked.clone());
90 let new_parent_work_submitted =
91 W::add(self.parent_work_submitted.clone(), parent_worked)
92 .unwrap()
93 .clone();
94 self.parent_work_submitted = new_parent_work_submitted;
95 } else {
96 let remaining_parent_work =
102 self.parent_work.clone() - self.parent_work_submitted.clone();
103 self.parent.worked(remaining_parent_work.clone());
104 let new_parent_work_submitted =
105 W::add(self.parent_work_submitted.clone(), remaining_parent_work)
106 .unwrap()
107 .clone();
108 self.parent_work_submitted = new_parent_work_submitted;
109 }
110 }
111
112 fn total(&self) -> &W {
113 &self.sub_work
114 }
115
116 fn completed(&self) -> &W {
117 &self.sub_work_completed
118 }
119
120 fn remaining(&self) -> Cow<W> {
121 Cow::Owned(self.sub_work.clone() - self.sub_work_completed.clone())
122 }
123
124 fn close(&mut self) -> Result<(), crate::CloseError> {
125 if self.closed.is_none() {
126 let work_left = self.remaining();
127 let result = if work_left.as_ref() == &W::zero() {
128 Ok(())
129 } else {
130 Err(crate::CloseError { msg: format!("Must not close progress monitor {self:#?} when work left is {work_left} which is != 0.") })
131 };
132 self.closed = Some(result.clone()); result
134 } else {
135 self.closed.clone().unwrap()
137 }
138 }
139}
140
141impl<'p2, 'n2, 'p, 'n, N, W, A1, A2, P> ProgressMonitorDivision<'p, 'n, N, W, A1, A2>
142 for ChildMonitor<'n2, 'p2, W, P>
143where
144 Self: ProgressMonitor<W> + Sized,
145 N: Into<Cow<'n, str>>,
146 W: Work,
147 A1: Into<W>,
148 A2: Into<W>,
149 P: ProgressMonitor<W>,
150{
151 fn new_child(
152 &'p mut self,
153 name: N,
154 amount_of_parent_work: A1,
155 amount_of_child_work: A2,
156 ) -> ChildMonitor<'n, 'p, W, Self> {
157 let amount_of_parent_work: W = amount_of_parent_work.into();
158 let amount_of_child_work: W = amount_of_child_work.into();
159
160 assert!(&amount_of_parent_work <= self.remaining().as_ref());
162
163 ChildMonitor::new(
164 name.into(),
165 self,
166 amount_of_parent_work,
167 amount_of_child_work,
168 )
169 }
170}
171
172impl<'n, 'p, W: Work, T: ProgressMonitor<W>> Display for ChildMonitor<'n, 'p, W, T> {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 f.write_fmt(format_args!(
175 "{}/{}",
176 self.sub_work_completed, self.sub_work
177 ))
178 }
179}
180
181impl<'n, 'p, W: Work, T: ProgressMonitor<W>> Drop for ChildMonitor<'n, 'p, W, T> {
182 fn drop(&mut self) {
183 match &self.closed {
184 Some(result) => match result {
185 Ok(()) => { }
186 Err(err) => {
187 tracing::error!(
188 "SubMonitor was not successfully closed. Reason: {}",
189 err.msg
190 );
191 }
192 },
193 None => {
194 tracing::warn!("close() was not called on {self:?}!");
195 self.close().expect("Successful close");
196 }
197 }
198 }
199}