va_ts/
duration_fmt.rs

1//! golang style duration format wrapper
2use std::cmp;
3use std::fmt;
4use std::time::Duration;
5
6pub struct DurationFmt(pub Duration);
7
8impl DurationFmt {
9    pub fn from_nanos(nanos: u64) -> DurationFmt {
10        DurationFmt(Duration::from_nanos(nanos))
11    }
12
13    #[inline(always)]
14    fn duration(&self) -> Duration {
15        self.0
16    }
17
18    #[inline(always)]
19    fn pure_nanos(&self) -> u128 {
20        self.0.as_nanos() % Duration::from_micros(1).as_nanos()
21    }
22
23    #[inline(always)]
24    fn pure_micros(&self) -> u128 {
25        (self.0.as_nanos() % Duration::from_millis(1).as_nanos())
26            / Duration::from_micros(1).as_nanos()
27    }
28
29    #[inline(always)]
30    fn pure_millis(&self) -> u128 {
31        (self.0.as_nanos() % Duration::from_secs(1).as_nanos())
32            / Duration::from_millis(1).as_nanos()
33    }
34
35    #[inline(always)]
36    fn pure_secs_as_f64(&self) -> f64 {
37        ((self.0.as_nanos() % Duration::from_secs(60).as_nanos()) as f64)
38            / (Duration::from_secs(1).as_nanos() as f64)
39    }
40
41    #[inline(always)]
42    fn pure_mins(&self) -> u128 {
43        (self.0.as_nanos() % Duration::from_secs(60 * 60).as_nanos())
44            / Duration::from_secs(60).as_nanos()
45    }
46
47    #[inline(always)]
48    fn pure_hours(&self) -> u128 {
49        self.0.as_nanos() / Duration::from_secs(60 * 60).as_nanos()
50    }
51}
52
53impl cmp::PartialEq for DurationFmt {
54    fn eq(&self, other: &Self) -> bool {
55        self.duration() == other.duration()
56    }
57}
58
59impl From<Duration> for DurationFmt {
60    #[inline(always)]
61    fn from(d: Duration) -> Self {
62        DurationFmt(d)
63    }
64}
65
66impl fmt::Display for DurationFmt {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        match self.duration() {
69            d if d <= Duration::from_micros(1) => write!(f, "{}ns", self.pure_nanos()),
70            d if d <= Duration::from_millis(1) => {
71                let ns = self.pure_nanos();
72                let mcs = self.pure_micros();
73
74                match ns {
75                    0 => write!(f, "{}us", mcs),
76                    _ => write!(f, "{}us{}ns", mcs, ns),
77                }
78            }
79            d if d <= (Duration::from_secs(1) / 10) => {
80                let mcs = self.pure_micros();
81                let ms = self.pure_millis();
82
83                match mcs {
84                    0 => write!(f, "{}ms", ms),
85                    _ => write!(f, "{}ms{}us", ms, mcs),
86                }
87            }
88            _ => {
89                let h = self.pure_hours();
90                let m = self.pure_mins();
91                let s = self.pure_secs_as_f64();
92
93                if h != 0 {
94                    write!(f, "{}h", h)?;
95                }
96
97                if m != 0 {
98                    write!(f, "{}m", m)?;
99                }
100
101                if s != 0.0 {
102                    write!(f, "{:.2}s", s)
103                } else {
104                    Ok(())
105                }
106            }
107        }
108    }
109}
110
111impl fmt::Debug for DurationFmt {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        write!(f, "{}", self)
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::DurationFmt;
120
121    use std::time::Duration;
122
123    #[test]
124    fn fmt_ns() {
125        assert_eq!(format!("{}", DurationFmt::from_nanos(1)), "1ns");
126    }
127
128    #[test]
129    fn fmt_h_m_s() {
130        assert_eq!(
131            format!(
132                "{}",
133                DurationFmt::from(
134                    Duration::from_secs(10*3600) + // 10h
135                    Duration::from_secs(30*60) + // 30m
136                    Duration::from_secs(15) + // 15s
137                    Duration::from_millis(100) // 0.1s
138                )
139            ),
140            "10h30m15.10s"
141        );
142    }
143
144    #[test]
145    fn fmt_ms_us() {
146        assert_eq!(
147            format!(
148                "{}",
149                DurationFmt::from(
150                    Duration::from_millis(23) + // 23ms
151                    Duration::from_micros(17) + // 17us
152                    Duration::from_nanos(40) // 40ns
153                )
154            ),
155            "23ms17us"
156        );
157    }
158}