1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use super::{rounded, HumanCount, SPACE};
use std::fmt;
const SPEC: &[&str] = {
match (cfg!(feature = "iec"), cfg!(feature = "1024")) {
(true, _) => &["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"],
(false, false) => &["", "k", "M", "G", "T", "P", "E", "Z", "Y"],
(false, true) => &["", "K", "M", "G", "T", "P", "E", "Z", "Y"],
}
};
const DECIMALS: &[usize] = &[1, 1, 1, 2, 2, 2, 2, 2, 2];
const DIVISOR: f64 = {
match cfg!(feature = "1024") {
true => 1024.,
false => 1000.,
}
};
impl<T: AsRef<str>> fmt::Display for HumanCount<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (mut val, unit) = (self.0, self.1.as_ref());
for (&scale, &dec) in SPEC.iter().zip(DECIMALS) {
match rounded(val, dec) {
r if r.abs() >= DIVISOR => val /= DIVISOR,
r if r.fract() == 0. => return write!(f, "{r:.0}{SPACE}{scale}{unit}"),
r if (r * 10.).fract() == 0. => return write!(f, "{r:.1}{SPACE}{scale}{unit}"),
r => return write!(f, "{r:.dec$}{SPACE}{scale}{unit}"),
}
}
write!(f, "{val:.2}{SPACE}+{unit}")
}
}
impl<T: AsRef<str>> PartialEq<HumanCount<T>> for &str {
fn eq(&self, other: &HumanCount<T>) -> bool {
*self == &other.to_string()
}
}
impl<T: AsRef<str>> PartialEq<&str> for HumanCount<T> {
fn eq(&self, other: &&str) -> bool {
&self.to_string() == other
}
}
#[cfg(test)]
mod tests {
use crate::HumanRepr;
#[test]
fn operation() {
assert_eq!("123 kB", 123000_u64.human_count_bytes());
assert_eq!("123.5 kB", 123456_u64.human_count_bytes());
assert_eq!("23 B", 23u8.human_count_bytes());
assert_eq!("23 B", 23i8.human_count_bytes());
assert_eq!("-23 B", (-23i8).human_count_bytes());
assert_eq!("1 kB", 1025u16.human_count_bytes());
assert_eq!("-1 kB", (-1025i16).human_count_bytes());
assert_eq!("43.2 MB", 43214321u32.human_count_bytes());
assert_eq!("23.4 GB", 23403454432_u64.human_count_bytes());
assert_eq!("23.43 GB", 23433454432_u64.human_count_bytes());
assert_eq!("18.45 EB", u64::MAX.human_count_bytes());
assert_eq!("9.22 EB", i64::MAX.human_count_bytes());
assert_eq!("-9.22 EB", i64::MIN.human_count_bytes());
assert_eq!("340282366920.94 +B", u128::MAX.human_count_bytes());
}
#[test]
fn flexibility() {
assert_eq!("123 MCrabs", 123e6.human_count("Crabs"));
assert_eq!("123 MCrabs", 123e6.human_count("Crabs".to_owned()));
assert_eq!("123 k🦀", 123e3.human_count("🦀"));
}
#[test]
fn ownership() {
let mut a = 42000;
assert_eq!("42 kB", a.human_count_bytes());
assert_eq!("42 kB", (&a).human_count_bytes());
assert_eq!("42 kB", (&mut a).human_count_bytes());
}
}