1use crate::prelude::*;
6
7#[derive(Debug,Clone,Serialize,Deserialize,IntoOwned)]
8pub struct ProgressInfo<'pi> {
9 pub phase: Count<'pi>,
10 pub item: Count<'pi>,
11}
12
13#[derive(Debug,Clone,Serialize,Deserialize,IntoOwned)]
14pub struct Count<'pi> {
15 pub value: Value,
16 pub desc: Cow<'pi, str>,
17}
18
19#[derive(Debug,Clone,Serialize,Deserialize,IntoOwned)]
20#[derive(Educe)]
21#[educe(Default)]
22pub enum Value {
23 #[educe(Default)] Exact {
24 i: usize,
25 n: usize,
26 },
27 Fraction {
28 f: f32, }
30}
31
32impl Value {
33 pub fn fraction(&self) -> f32 {
34 match self {
35 &Value::Exact{ i:_, n } if n == 0 => 0.,
36 &Value::Exact{ i, n } => (i as f32) / (n as f32),
37 &Value::Fraction{ f } => f,
38 }
39 }
40}
41
42pub trait Originator {
43 fn report(&mut self, info: ProgressInfo<'_>);
44 fn phase_begin_(&mut self, phase: Count<'_>, len: usize);
45 fn item_(&mut self, item: usize, desc: Cow<'_, str>);
46}
47
48pub struct ResponseOriginator<'c,'w,W,F> where W: Write {
49 chan: &'c mut ResponseWriter<'w,W>,
50 phase: Count<'static>,
51 len: usize,
52 formatter: F,
53}
54impl<'c,'w,W,F> ResponseOriginator<'c,'w,W,F> where W: Write {
55 pub fn new(chan: &'c mut ResponseWriter<'w,W>,
56 formatter: F) -> Self {
57 Self {
58 chan,
59 phase: Count { value: default(), desc: Cow::Borrowed("") },
60 len: 0,
61 formatter,
62 }
63 }
64}
65
66impl<W,F,M> Originator for ResponseOriginator<'_,'_,W,F>
67where W: Write,
68 F: Fn(ProgressInfo<'_>) -> M,
69 M: Serialize,
70{
71 fn report(&mut self, pi: ProgressInfo<'_>) {
72 let resp = (self.formatter)(pi);
73 self.chan.progress_with(resp).unwrap_or(());
74 }
75 fn phase_begin_(&mut self, phase: Count<'_>, len: usize) {
76 self.phase = phase.into_owned();
77 self.len = len;
78 }
79 fn item_(&mut self, item: usize, desc: Cow<'_, str>) {
80 let value = Value::Exact { i: item, n: self.len };
81 self.report(ProgressInfo {
82 phase: self.phase.clone(),
83 item: Count { value, desc }
84 })
85 }
86}
87
88#[allow(unused_variables)]
89impl Originator for () {
90 fn report(&mut self, pi: ProgressInfo<'_>) { }
91 fn phase_begin_(&mut self, phase: Count<'_>, len: usize) { }
92 fn item_(&mut self, item: usize, desc: Cow<'_, str>) { }
93}
94
95pub trait Enum: EnumCount + ToPrimitive + EnumMessage { }
96impl<T> From<T> for Count<'static> where T: Enum {
97 fn from(t: T) -> Count<'static> {
98 let value = Value::Exact {
99 i: t.to_usize().unwrap(),
100 n: T::COUNT - 1,
101 };
102 Count {
103 value,
104 desc: Cow::Owned(t.get_message().unwrap_or("...").to_owned()),
106 }
107 }
108}
109impl<'t> From<&'t str> for Count<'t> {
110 fn from(s: &'t str) -> Count<'t> {
111 Count { value: default(), desc: Cow::Borrowed(s) }
112 }
113}
114impl From<String> for Count<'static> {
115 fn from(s: String) -> Count<'static> {
116 Count { value: default(), desc: Cow::Owned(s) }
117 }
118}
119impl<'t> From<()> for Count<'t> { fn from(_:()) -> Count<'t> {
120 Count { value: default(), desc: Cow::Borrowed("") }
121} }
122
123#[ext(pub, name=OriginatorExt)]
124impl &'_ mut (dyn Originator + '_) {
125 fn phase_item<'p,'e,P,E>(&mut self, phase: P, item: E)
126 where P: Into<Count<'p>>,
127 E: Into<Count<'e>>,
128 {
129 let phase = phase.into();
130 let item = item .into();
131 self.report(ProgressInfo { phase, item });
132 }
133
134 fn phase<'p,P>(&mut self, phase: P, len: usize)
135 where P: Into<Count<'p>>,
136 {
137 self.phase_begin_(phase.into(), len)
138 }
139
140 fn item<'s,S>(&mut self, item: usize, desc: S)
141 where S: Into<Cow<'s, str>>,
142 {
143 self.item_(item, desc.into())
144 }
145}
146
147pub struct ReadOriginator<'o,R:Read> {
148 r: R,
149 total_len: usize,
150 orig: &'o mut dyn Originator,
151 counter: usize,
153 last_report: usize,
154}
155
156impl<'oo,'o,R:Read> ReadOriginator<'o,R> {
157 pub fn new<'p,P>(mut orig: &'o mut dyn Originator, phase: P,
158 total_len: usize, r: R) -> Self
159 where P: Into<Count<'p>>
160 {
161 orig.phase(phase, total_len);
162 let mut ro = ReadOriginator {
163 r, orig, total_len,
164 counter: 0,
165 last_report: 0,
166 };
167 ro.report();
168 ro
169 }
170
171 fn report(&mut self) {
172 let t = self.total_len.to_string();
173 let c = format!("{:>width$}", self.counter, width=t.len());
174 let m = |s: String| {
175 izip!( iter::once("").chain(["",""," "].iter().cloned().cycle()),
176 s.chars().rev() )
177 .map(|(s,c)| [s.chars().next(), Some(c)])
178 .flatten()
179 .flatten()
180 .collect::<String>()
181 .chars().rev()
182 .collect::<String>()
183 };
184 let desc = format!(" {} of {}", m(c), m(t));
185 self.orig.item(self.counter, desc);
186 self.last_report = self.counter;
187 }
188}
189
190impl<R:Read> Read for ReadOriginator<'_,R> {
191 #[throws(io::Error)]
192 fn read(&mut self, buf: &mut [u8]) -> usize {
193 let got = self.r.read(buf)?;
194 self.counter += got;
195 if self.counter - self.last_report > 10000 {
196 self.report();
197 }
198 got
199 }
200}