human_repr/
human_throughput.rs

1use super::HumanThroughputData;
2use crate::utils::{self, SPACE};
3use std::fmt::{self, Debug, Display};
4
5const SPEC: &[(f64, &str, usize)] = &[
6    (24., "/d", 2),
7    (60., "/h", 1),
8    (60., "/min", 1),
9    // "/s" in code.
10];
11
12impl Display for HumanThroughputData<'_> {
13    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14        let HumanThroughputData { mut val, unit } = self;
15        val *= 60. * 60. * 24.;
16        for &(size, scale, dec) in SPEC {
17            match utils::rounded(val, dec) {
18                r if r.abs() >= size => val /= size,
19                r if r.fract() == 0. => return write!(f, "{:.0}{}{}{}", r, SPACE, unit, scale),
20                r if (r * 10.).fract() == 0. => {
21                    return write!(f, "{:.1}{}{}{}", r, SPACE, unit, scale)
22                }
23                r => return write!(f, "{:.2}{}{}{}", r, SPACE, unit, scale),
24            }
25        }
26
27        use super::HumanCount;
28        write!(f, "{}/s", val.human_count(unit.as_ref()))
29    }
30}
31
32impl Debug for HumanThroughputData<'_> {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        let mut ds = f.debug_struct("HumanThroughput");
35        ds.field("val", &self.val);
36        ds.field("unit", &self.unit);
37        ds.finish()?;
38        write!(f, " -> ")?;
39        fmt::Display::fmt(self, f)
40    }
41}
42
43impl PartialEq<HumanThroughputData<'_>> for &str {
44    fn eq(&self, other: &HumanThroughputData<'_>) -> bool {
45        utils::display_compare(self, other)
46    }
47}
48
49impl PartialEq<&str> for HumanThroughputData<'_> {
50    fn eq(&self, other: &&str) -> bool {
51        other == self
52    }
53}
54
55#[cfg(all(test, not(any(feature = "1024", feature = "iec", feature = "space"))))]
56mod tests {
57    use crate::HumanThroughput;
58
59    #[test]
60    fn operation() {
61        assert_eq!("1B/s", 1.human_throughput_bytes());
62        assert_eq!("-1B/s", (-1).human_throughput_bytes());
63        assert_eq!("1.2MB/s", (1234567. / 1.).human_throughput_bytes());
64        assert_eq!("10B/s", (10. / 1.).human_throughput_bytes());
65        assert_eq!("30B/min", (1. / 2.).human_throughput_bytes());
66        assert_eq!("-30B/min", (-1. / 2.).human_throughput_bytes());
67        assert_eq!("5B/s", (10. / 2.).human_throughput_bytes());
68        assert_eq!("5.5B/s", (11. / 2.).human_throughput_bytes());
69        assert_eq!("6.1B/min", (10. / 99.).human_throughput_bytes());
70        assert_eq!("1.8B/min", (3. / 100.).human_throughput_bytes());
71        assert_eq!("4.4B/min", (8. / 110.).human_throughput_bytes());
72        assert_eq!("6.8B/h", (3. / 1600.).human_throughput_bytes());
73        assert_eq!("1.9kB/s", (3000000. / 1600.).human_throughput_bytes());
74        assert_eq!("4.8B/min", (5432737. / 67587655.).human_throughput_bytes());
75        assert_eq!("28.9B/h", (5432737. / 675876554.).human_throughput_bytes());
76        assert_eq!("8B/s", (5432737542. / 675876554.).human_throughput_bytes());
77        assert_eq!("1B/s", (1. / 0.99).human_throughput_bytes());
78        assert_eq!("1B/s", (1. / 0.999).human_throughput_bytes());
79        assert_eq!("1B/s", (1. / 1.00001).human_throughput_bytes());
80        assert_eq!("1B/s", (1. / 1.0001).human_throughput_bytes());
81        assert_eq!("9B/d", (125. / 1200000.).human_throughput_bytes());
82        assert_eq!("9.5B/d", (132. / 1200000.).human_throughput_bytes());
83        assert_eq!("9.72B/d", (135. / 1200000.).human_throughput_bytes());
84        assert_eq!("1B/h", (1. / 3599.).human_throughput_bytes());
85        assert_eq!("1B/h", (1. / 3600.).human_throughput_bytes());
86        assert_eq!("23.99B/d", (1. / 3601.).human_throughput_bytes());
87        assert_eq!("23.95B/d", (1. / 3608.).human_throughput_bytes());
88        assert_eq!("2.16B/d", (2. / 80000.).human_throughput_bytes());
89    }
90
91    #[test]
92    fn flexibility() {
93        assert_eq!("123MCrabs/s", 123e6.human_throughput("Crabs"));
94        assert_eq!("123MCrabs/s", 123e6.human_throughput("Crabs".to_owned()));
95        assert_eq!("123MCrabs/s", 123e6.human_throughput(&"Crabs".to_owned()));
96        assert_eq!("123M🦀/s", 123e6.human_throughput("🦀"));
97        assert_eq!("12.3k°C/s", 123e2.human_throughput("°C"));
98        assert_eq!("1.2°C/s", 123e-2.human_throughput("°C"));
99    }
100
101    #[test]
102    #[allow(clippy::needless_borrow)]
103    fn ownership() {
104        let mut a = 42000;
105        assert_eq!("42kB/s", a.human_throughput_bytes());
106        assert_eq!("42kB/s", (&a).human_throughput_bytes());
107        assert_eq!("42kB/s", (&mut a).human_throughput_bytes());
108    }
109
110    #[test]
111    fn symmetric() {
112        assert_eq!(1.human_throughput_bytes(), "1B/s");
113    }
114}
115
116#[test]
117#[cfg(feature = "serde")]
118fn serialize() -> Result<(), serde_json::Error> {
119    use crate::HumanThroughput;
120    let h = 123456.human_throughput("X");
121    let ser = serde_json::to_string(&h)?;
122    assert_eq!(r#"{"val":123456.0,"unit":"X"}"#, &ser);
123    let h2 = serde_json::from_str::<HumanThroughputData>(&ser)?;
124    assert_eq!(h, h2);
125    Ok(())
126}