1use std::{fmt, hash::Hasher};
2
3use crate::{progress::Step, unit::display};
4
5pub trait DisplayValue {
7 fn display_current_value(&self, w: &mut dyn fmt::Write, value: Step, _upper: Option<Step>) -> fmt::Result {
12 fmt::write(w, format_args!("{}", value))
13 }
14 fn separator(&self, w: &mut dyn fmt::Write, _value: Step, _upper: Option<Step>) -> fmt::Result {
19 w.write_str("/")
20 }
21
22 fn display_upper_bound(&self, w: &mut dyn fmt::Write, upper_bound: Step, _value: Step) -> fmt::Result {
26 fmt::write(w, format_args!("{}", upper_bound))
27 }
28
29 fn dyn_hash(&self, state: &mut dyn std::hash::Hasher);
33
34 fn display_unit(&self, w: &mut dyn fmt::Write, value: Step) -> fmt::Result;
38
39 fn display_percentage(&self, w: &mut dyn fmt::Write, percentage: f64) -> fmt::Result {
41 w.write_fmt(format_args!("[{}%]", percentage as usize))
42 }
43
44 fn display_throughput(&self, w: &mut dyn fmt::Write, throughput: &display::Throughput) -> fmt::Result {
46 let (fraction, unit) = self.fraction_and_time_unit(throughput.timespan);
47 w.write_char('|')?;
48 self.display_current_value(w, throughput.value_change_in_timespan, None)?;
49 w.write_char('/')?;
50 match fraction {
51 Some(fraction) => w.write_fmt(format_args!("{}", fraction)),
52 None => Ok(()),
53 }?;
54 w.write_fmt(format_args!("{}|", unit))
55 }
56
57 fn fraction_and_time_unit(&self, timespan: std::time::Duration) -> (Option<f64>, &'static str) {
59 fn skip_one(v: f64) -> Option<f64> {
60 if (v - 1.0).abs() < f64::EPSILON {
61 None
62 } else {
63 Some(v)
64 }
65 }
66 const HOUR_IN_SECS: u64 = 60 * 60;
67 let secs = timespan.as_secs();
68 let h = secs / HOUR_IN_SECS;
69 if h > 0 {
70 return (skip_one(secs as f64 / HOUR_IN_SECS as f64), "h");
71 }
72 const MINUTES_IN_SECS: u64 = 60;
73 let m = secs / MINUTES_IN_SECS;
74 if m > 0 {
75 return (skip_one(secs as f64 / MINUTES_IN_SECS as f64), "m");
76 }
77 if secs > 0 {
78 return (skip_one(secs as f64), "s");
79 }
80
81 (skip_one(timespan.as_millis() as f64), "ms")
82 }
83}
84
85impl DisplayValue for &'static str {
86 fn dyn_hash(&self, state: &mut dyn Hasher) {
87 state.write(self.as_bytes())
88 }
89
90 fn display_unit(&self, w: &mut dyn fmt::Write, _value: usize) -> fmt::Result {
91 w.write_fmt(format_args!("{}", self))
92 }
93}