1use core::{
30 cmp::Ordering,
31 fmt::{self, Display, Formatter},
32 hash::{Hash, Hasher},
33};
34
35#[cfg(test)]
36mod tests;
37
38const N1024: u32 = 1024;
39const N1024_P2: u32 = N1024.pow(2);
40
41#[derive(Debug, Clone, Copy, Eq)]
43pub enum Memory {
44
45 KiB(u32),
47
48 MiB(u32),
50
51 GiB(u32),
53
54}
55
56impl Memory {
57
58 pub (crate) const fn to_kib(&self) -> Option<u32> {
60 match self {
61 Self::KiB(k) => Some(*k),
62 Self::MiB(m) => m.checked_mul(N1024),
63 Self::GiB(g) => g.checked_mul(N1024_P2),
64 }
65 }
66
67 const fn to_kib_u64(&self) -> u64 {
69 match self {
70 Self::KiB(k) => *k as u64,
71 Self::MiB(m) => *m as u64 * N1024 as u64,
72 Self::GiB(g) => *g as u64 * N1024_P2 as u64,
73 }
74 }
75
76}
77
78impl Display for Memory {
79
80 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
81 const KIB: &str = "KiB";
82 const MIB: &str = "MiB";
83 const GIB: &str = "GiB";
84
85 let mib = |m| if m == 0 || m % N1024 != 0 { (m, MIB) } else { (m / N1024, GIB) };
86 let (v, unit) = match self {
87 Self::KiB(k) => if k == &0 || k % N1024 != 0 { (*k, KIB) } else { mib(k / N1024) },
88 Self::MiB(m) => mib(*m),
89 Self::GiB(g) => (*g, GIB),
90 };
91 write!(f, concat!("{v}", ' ', "{unit}"), v=v, unit=unit)
92 }
93
94}
95
96impl Hash for Memory {
97
98 fn hash<H>(&self, h: &mut H) where H: Hasher {
99 self.to_kib_u64().hash(h);
100 }
101
102}
103
104impl PartialEq for Memory {
105
106 fn eq(&self, other: &Self) -> bool {
107 self.cmp(other) == Ordering::Equal
108 }
109
110}
111
112impl Ord for Memory {
113
114 fn cmp(&self, other: &Self) -> Ordering {
115 self.to_kib_u64().cmp(&other.to_kib_u64())
116 }
117
118}
119
120impl PartialOrd for Memory {
121
122 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
123 Some(self.cmp(other))
124 }
125
126}