1 // Copyright 2020-2021 Ian Jackson and contributors to Otter
2 // SPDX-License-Identifier: AGPL-3.0-or-later
3 // There is NO WARRANTY.
7 #[derive(Debug,Clone,Serialize,Deserialize,IntoOwned)]
8 pub struct ProgressInfo<'pi> {
13 #[derive(Debug,Clone,Serialize,Deserialize,IntoOwned)]
14 pub struct Count<'pi> {
16 pub desc: Cow<'pi, str>,
19 #[derive(Debug,Clone,Serialize,Deserialize,IntoOwned)]
23 #[educe(Default)] Exact {
33 pub fn fraction(&self) -> f32 {
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,
42 pub 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>);
48 pub struct ResponseOriginator<'c,'w,W,F> where W: Write {
49 chan: &'c mut ResponseWriter<'w,W>,
50 phase: Count<'static>,
54 impl<'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 {
59 phase: Count { value: default(), desc: Cow::Borrowed("") },
66 impl<W,F,M> Originator for ResponseOriginator<'_,'_,W,F>
68 F: Fn(ProgressInfo<'_>) -> M,
71 fn report(&mut self, pi: ProgressInfo<'_>) {
72 let resp = (self.formatter)(pi);
73 self.chan.progress_with(resp).unwrap_or(());
75 fn phase_begin_(&mut self, phase: Count<'_>, len: usize) {
76 self.phase = phase.into_owned();
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 }
88 #[allow(unused_variables)]
89 impl 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>) { }
95 pub trait Enum: EnumCount + ToPrimitive + EnumMessage { }
96 impl<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(),
104 // Show be Borrowed https://github.com/Peternator7/strum/issues/159
105 desc: Cow::Owned(t.get_message().unwrap_or("...").to_owned()),
109 impl<'t> From<&'t str> for Count<'t> {
110 fn from(s: &'t str) -> Count<'t> {
111 Count { value: default(), desc: Cow::Borrowed(s) }
114 impl From<String> for Count<'static> {
115 fn from(s: String) -> Count<'static> {
116 Count { value: default(), desc: Cow::Owned(s) }
119 impl<'t> From<()> for Count<'t> { fn from(_:()) -> Count<'t> {
120 Count { value: default(), desc: Cow::Borrowed("") }
123 #[ext(pub, name=OriginatorExt)]
124 impl &'_ mut (dyn Originator + '_) {
125 fn phase_item<'p,'e,P,E>(&mut self, phase: P, item: E)
126 where P: Into<Count<'p>>,
129 let phase = phase.into();
130 let item = item .into();
131 self.report(ProgressInfo { phase, item });
134 fn phase<'p,P>(&mut self, phase: P, len: usize)
135 where P: Into<Count<'p>>,
137 self.phase_begin_(phase.into(), len)
140 fn item<'s,S>(&mut self, item: usize, desc: S)
141 where S: Into<Cow<'s, str>>,
143 self.item_(item, desc.into())
147 pub struct ReadOriginator<'o,R:Read> {
150 orig: &'o mut dyn Originator,
156 impl<'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>>
161 orig.phase(phase, total_len);
162 let mut ro = ReadOriginator {
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()),
177 .map(|(s,c)| [s.chars().next(), Some(c)])
184 let desc = format!(" {} of {}", m(c), m(t));
185 self.orig.item(self.counter, desc);
186 self.last_report = self.counter;
190 impl<R:Read> Read for ReadOriginator<'_,R> {
192 fn read(&mut self, buf: &mut [u8]) -> usize {
193 let got = self.r.read(buf)?;
195 if self.counter - self.last_report > 10000 {