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 ];
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}