1use crate::Bytes;
5use crate::impl_comparison;
6use core::fmt;
7use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
8
9pub const KB_BYTES: u64 = 1000;
11pub const MB_BYTES: u64 = 1000 * KB_BYTES;
13pub const GB_BYTES: u64 = 1000 * MB_BYTES;
15pub const TB_BYTES: u64 = 1000 * GB_BYTES;
17pub const PB_BYTES: u64 = 1000 * TB_BYTES;
19
20macro_rules! impl_unit {
21 ($name:ident, $unit_str:expr, $multiplier:expr) => {
22 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
23 pub struct $name(pub u64);
24
25 impl $name {
26 pub const fn new(val: u64) -> Self {
27 Self(val)
28 }
29
30 pub const fn as_u64(&self) -> u64 {
31 self.0
32 }
33
34 pub const fn as_bytes(self) -> Bytes {
35 Bytes(self.0 * $multiplier)
36 }
37
38 pub const fn as_kb(self) -> KB {
39 KB((self.0 * $multiplier) / KB_BYTES)
40 }
41
42 pub const fn as_mb(self) -> MB {
43 MB((self.0 * $multiplier) / MB_BYTES)
44 }
45
46 pub const fn as_gb(self) -> GB {
47 GB((self.0 * $multiplier) / GB_BYTES)
48 }
49
50 pub const fn as_tb(self) -> TB {
51 TB((self.0 * $multiplier) / TB_BYTES)
52 }
53
54 pub const fn as_pb(self) -> PB {
55 PB((self.0 * $multiplier) / PB_BYTES)
56 }
57 }
58
59 impl fmt::Display for $name {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 write!(f, "{} {}", self.0, $unit_str)
62 }
63 }
64
65 impl Add for $name {
66 type Output = Self;
67 fn add(self, rhs: Self) -> Self::Output {
68 Self(self.0 + rhs.0)
69 }
70 }
71 impl AddAssign for $name {
72 fn add_assign(&mut self, rhs: Self) {
73 self.0 += rhs.0;
74 }
75 }
76
77 impl Sub for $name {
78 type Output = Self;
79 fn sub(self, rhs: Self) -> Self::Output {
80 Self(self.0 - rhs.0)
81 }
82 }
83 impl SubAssign for $name {
84 fn sub_assign(&mut self, rhs: Self) {
85 self.0 -= rhs.0;
86 }
87 }
88
89 impl Mul<u64> for $name {
90 type Output = Self;
91 fn mul(self, rhs: u64) -> Self::Output {
92 Self(self.0 * rhs)
93 }
94 }
95 impl Mul<$name> for u64 {
96 type Output = $name;
97 fn mul(self, rhs: $name) -> Self::Output {
98 $name(self * rhs.0)
99 }
100 }
101
102 impl MulAssign<u64> for $name {
103 fn mul_assign(&mut self, rhs: u64) {
104 self.0 *= rhs;
105 }
106 }
107
108 impl Div<u64> for $name {
109 type Output = Self;
110 fn div(self, rhs: u64) -> Self::Output {
111 Self(self.0 / rhs)
112 }
113 }
114 impl DivAssign<u64> for $name {
115 fn div_assign(&mut self, rhs: u64) {
116 self.0 /= rhs;
117 }
118 }
119
120 impl Div for $name {
121 type Output = u64;
122 fn div(self, rhs: Self) -> Self::Output {
123 self.0 / rhs.0
124 }
125 }
126
127 impl Rem for $name {
128 type Output = Self;
129 fn rem(self, rhs: Self) -> Self::Output {
130 Self(self.0 % rhs.0)
131 }
132 }
133
134 impl RemAssign for $name {
135 fn rem_assign(&mut self, rhs: Self) {
136 self.0 %= rhs.0;
137 }
138 }
139 };
140}
141
142impl_unit!(KB, "KB", KB_BYTES);
143impl_unit!(MB, "MB", MB_BYTES);
144impl_unit!(GB, "GB", GB_BYTES);
145impl_unit!(TB, "TB", TB_BYTES);
146impl_unit!(PB, "PB", PB_BYTES);
147
148impl From<KB> for Bytes {
150 fn from(val: KB) -> Self {
151 Self(val.0 * KB_BYTES)
152 }
153}
154
155impl From<MB> for Bytes {
156 fn from(val: MB) -> Self {
157 Self(val.0 * MB_BYTES)
158 }
159}
160
161impl From<GB> for Bytes {
162 fn from(val: GB) -> Self {
163 Self(val.0 * GB_BYTES)
164 }
165}
166
167impl From<TB> for Bytes {
168 fn from(val: TB) -> Self {
169 Self(val.0 * TB_BYTES)
170 }
171}
172
173impl From<PB> for Bytes {
174 fn from(val: PB) -> Self {
175 Self(val.0 * PB_BYTES)
176 }
177}
178
179impl From<MB> for KB {
181 fn from(val: MB) -> Self {
182 Self(val.0 * 1000)
183 }
184}
185impl From<GB> for MB {
186 fn from(val: GB) -> Self {
187 Self(val.0 * 1000)
188 }
189}
190impl From<TB> for GB {
191 fn from(val: TB) -> Self {
192 Self(val.0 * 1000)
193 }
194}
195impl From<PB> for TB {
196 fn from(val: PB) -> Self {
197 Self(val.0 * 1000)
198 }
199}
200
201impl_comparison!(Bytes, KB, MB, GB, TB, PB);
202impl_comparison!(KB, MB, GB, TB, PB);
203impl_comparison!(MB, GB, TB, PB);
204impl_comparison!(GB, TB, PB);
205impl_comparison!(TB, PB);
206
207#[cfg(test)]
208mod tests {
209 extern crate std;
210 use super::*;
211 use crate::Bytes;
212 use std::format;
213
214 #[test]
215 fn test_si_constants() {
216 assert_eq!(KB_BYTES, 1000);
217 assert_eq!(MB_BYTES, 1000 * 1000);
218 assert_eq!(GB_BYTES, 1000 * 1000 * 1000);
219 assert_eq!(TB_BYTES, 1000 * 1000 * 1000 * 1000);
220 assert_eq!(PB_BYTES, 1000 * 1000 * 1000 * 1000 * 1000);
221 }
222
223 #[test]
224 fn test_si_conversions() {
225 assert_eq!(Bytes::from(KB(1)), Bytes(1000));
226 assert_eq!(Bytes::from(MB(1)), Bytes(1000 * 1000));
227 assert_eq!(KB::from(MB(1)), KB(1000));
228 }
229
230 #[test]
231 fn test_si_arithmetic() {
232 assert_eq!(KB(10) + KB(20), KB(30));
233 assert_eq!(MB(50) - MB(20), MB(30));
234 assert_eq!(KB(10) * 5, KB(50));
235 assert_eq!(KB(100) / 2, KB(50));
236 }
237
238 #[test]
239 fn test_si_display() {
240 assert_eq!(format!("{}", KB(5)), "5 KB");
241 assert_eq!(format!("{}", MB(10)), "10 MB");
242 }
243
244 #[test]
245 fn test_si_comparisons() {
246 assert!(MB(1) == KB(1000));
247 assert!(MB(1) > KB(100));
248 }
249}