Skip to main content

typed_bytes/
si.rs

1//! SI Units
2//! For more information visit <https://en.wikipedia.org/wiki/Binary_prefix>
3
4use crate::Bytes;
5use crate::impl_comparison;
6use core::fmt;
7use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
8
9/// 1 KB = 1000 Bytes
10pub const KB_BYTES: u64 = 1000;
11/// 1 MB = 1000 * 1000 Bytes
12pub const MB_BYTES: u64 = 1000 * KB_BYTES;
13/// 1 GB = 1000 * 1000 * 1000 Bytes
14pub const GB_BYTES: u64 = 1000 * MB_BYTES;
15/// 1 TB = 1000 * 1000 * 1000 * 1000 Bytes
16pub const TB_BYTES: u64 = 1000 * GB_BYTES;
17/// 1 PB = 1000 * 1000 * 1000 * 1000 * 1000 Bytes
18pub 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
148// Conversions to Bytes
149impl 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
179// Conversions between SI units
180impl 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}