1use std::{fmt, ops};
2
3use super::Factor;
4
5pub trait ByteUnits {
7 fn bytes(self) -> ByteLength;
11 fn kibibytes(self) -> ByteLength;
15 fn kilobytes(self) -> ByteLength;
19
20 fn mebibytes(self) -> ByteLength;
24 fn megabytes(self) -> ByteLength;
28
29 fn gibibytes(self) -> ByteLength;
33 fn gigabytes(self) -> ByteLength;
37
38 fn tebibytes(self) -> ByteLength;
42 fn terabytes(self) -> ByteLength;
46}
47impl ByteUnits for usize {
48 fn bytes(self) -> ByteLength {
49 ByteLength(self)
50 }
51
52 fn kibibytes(self) -> ByteLength {
53 ByteLength::from_kibi(self)
54 }
55
56 fn kilobytes(self) -> ByteLength {
57 ByteLength::from_kilo(self)
58 }
59
60 fn mebibytes(self) -> ByteLength {
61 ByteLength::from_mebi(self)
62 }
63
64 fn megabytes(self) -> ByteLength {
65 ByteLength::from_mega(self)
66 }
67
68 fn gibibytes(self) -> ByteLength {
69 ByteLength::from_gibi(self)
70 }
71
72 fn gigabytes(self) -> ByteLength {
73 ByteLength::from_giga(self)
74 }
75
76 fn tebibytes(self) -> ByteLength {
77 ByteLength::from_tebi(self)
78 }
79
80 fn terabytes(self) -> ByteLength {
81 ByteLength::from_tera(self)
82 }
83}
84impl ByteUnits for f64 {
85 fn bytes(self) -> ByteLength {
86 ByteLength::from_byte_f64(self)
87 }
88
89 fn kibibytes(self) -> ByteLength {
90 ByteLength::from_kibi_f64(self)
91 }
92
93 fn kilobytes(self) -> ByteLength {
94 ByteLength::from_kilo_f64(self)
95 }
96
97 fn mebibytes(self) -> ByteLength {
98 ByteLength::from_mebi_f64(self)
99 }
100
101 fn megabytes(self) -> ByteLength {
102 ByteLength::from_mega_f64(self)
103 }
104
105 fn gibibytes(self) -> ByteLength {
106 ByteLength::from_gibi_f64(self)
107 }
108
109 fn gigabytes(self) -> ByteLength {
110 ByteLength::from_giga_f64(self)
111 }
112
113 fn tebibytes(self) -> ByteLength {
114 ByteLength::from_tebi_f64(self)
115 }
116
117 fn terabytes(self) -> ByteLength {
118 ByteLength::from_tera_f64(self)
119 }
120}
121
122#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, serde::Serialize, serde::Deserialize)]
127#[serde(transparent)]
128pub struct ByteLength(pub usize);
129impl From<usize> for ByteLength {
130 fn from(value: usize) -> Self {
131 Self(value)
132 }
133}
134impl ops::Add for ByteLength {
135 type Output = Self;
136
137 fn add(self, rhs: Self) -> Self::Output {
138 Self(self.0 + rhs.0)
139 }
140}
141impl ops::AddAssign for ByteLength {
142 fn add_assign(&mut self, rhs: Self) {
143 self.0 += rhs.0;
144 }
145}
146impl ops::Sub for ByteLength {
147 type Output = Self;
148
149 fn sub(self, rhs: Self) -> Self::Output {
150 Self(self.0 - rhs.0)
151 }
152}
153impl ops::SubAssign for ByteLength {
154 fn sub_assign(&mut self, rhs: Self) {
155 self.0 -= rhs.0;
156 }
157}
158impl ByteLength {
159 pub fn bytes(&self) -> usize {
163 self.0
164 }
165
166 fn scaled(self, scale: f64) -> f64 {
167 self.0 as f64 / scale
168 }
169
170 pub fn kibis(self) -> f64 {
172 self.scaled(1024.0)
173 }
174
175 pub fn kilos(self) -> f64 {
177 self.scaled(1000.0)
178 }
179
180 pub fn mebis(self) -> f64 {
182 self.scaled(1024.0f64.powi(2))
183 }
184
185 pub fn megas(self) -> f64 {
187 self.scaled(1000.0f64.powi(2))
188 }
189
190 pub fn gibis(self) -> f64 {
192 self.scaled(1024.0f64.powi(3))
193 }
194
195 pub fn gigas(self) -> f64 {
197 self.scaled(1000.0f64.powi(3))
198 }
199
200 pub fn tebis(self) -> f64 {
202 self.scaled(1024.0f64.powi(4))
203 }
204
205 pub fn teras(self) -> f64 {
207 self.scaled(1000.0f64.powi(4))
208 }
209
210 pub const MAX: ByteLength = ByteLength(usize::MAX);
212
213 pub const fn saturating_add(self, rhs: ByteLength) -> ByteLength {
215 ByteLength(self.0.saturating_add(rhs.0))
216 }
217
218 pub const fn saturating_sub(self, rhs: ByteLength) -> ByteLength {
220 ByteLength(self.0.saturating_sub(rhs.0))
221 }
222
223 pub const fn saturating_mul(self, rhs: ByteLength) -> ByteLength {
225 ByteLength(self.0.saturating_mul(rhs.0))
226 }
227
228 pub const fn wrapping_add(self, rhs: ByteLength) -> ByteLength {
236 ByteLength(self.0.wrapping_add(rhs.0))
237 }
238
239 pub const fn wrapping_sub(self, rhs: ByteLength) -> ByteLength {
241 ByteLength(self.0.wrapping_sub(rhs.0))
242 }
243
244 pub const fn wrapping_mul(self, rhs: ByteLength) -> ByteLength {
246 ByteLength(self.0.wrapping_mul(rhs.0))
247 }
248
249 pub const fn wrapping_div(self, rhs: ByteLength) -> ByteLength {
251 ByteLength(self.0.wrapping_div(rhs.0))
252 }
253
254 pub fn checked_add(self, rhs: ByteLength) -> Option<ByteLength> {
256 self.0.checked_add(rhs.0).map(ByteLength)
257 }
258
259 pub fn checked_sub(self, rhs: ByteLength) -> Option<ByteLength> {
261 self.0.checked_sub(rhs.0).map(ByteLength)
262 }
263
264 pub fn checked_mul(self, rhs: ByteLength) -> Option<ByteLength> {
266 self.0.checked_mul(rhs.0).map(ByteLength)
267 }
268
269 pub fn checked_div(self, rhs: ByteLength) -> Option<ByteLength> {
271 self.0.checked_div(rhs.0).map(ByteLength)
272 }
273}
274
275impl ByteLength {
277 pub const fn from_byte(bytes: usize) -> Self {
281 ByteLength(bytes)
282 }
283
284 pub const fn from_byte_f64(bytes: f64) -> Self {
288 ByteLength(bytes.round() as _)
289 }
290
291 const fn new(value: usize, scale: usize) -> Self {
292 ByteLength(value.saturating_mul(scale))
293 }
294
295 const fn new_f64(value: f64, scale: f64) -> Self {
296 ByteLength::from_byte_f64(value * scale)
297 }
298
299 pub const fn from_kibi(kibi_bytes: usize) -> Self {
303 Self::new(kibi_bytes, 1024)
304 }
305 pub const fn from_kibi_f64(kibi_bytes: f64) -> Self {
309 Self::new_f64(kibi_bytes, 1024.0)
310 }
311
312 pub const fn from_kilo(kilo_bytes: usize) -> Self {
316 Self::new(kilo_bytes, 1000)
317 }
318 pub const fn from_kilo_f64(kilo_bytes: f64) -> Self {
322 Self::new_f64(kilo_bytes, 1000.0)
323 }
324
325 pub const fn from_mebi(mebi_bytes: usize) -> Self {
329 Self::new(mebi_bytes, 1024usize.pow(2))
330 }
331 pub const fn from_mebi_f64(mebi_bytes: f64) -> Self {
335 Self::new_f64(mebi_bytes, 1024.0 * 1024.0)
336 }
337
338 pub const fn from_mega(mega_bytes: usize) -> Self {
342 Self::new(mega_bytes, 1000usize.pow(2))
343 }
344 pub const fn from_mega_f64(mebi_bytes: f64) -> Self {
348 Self::new_f64(mebi_bytes, 1000.0 * 1000.0)
349 }
350
351 pub const fn from_gibi(gibi_bytes: usize) -> Self {
355 Self::new(gibi_bytes, 1024usize.pow(3))
356 }
357 pub const fn from_gibi_f64(gibi_bytes: f64) -> Self {
361 Self::new_f64(gibi_bytes, 1024.0 * 1024.0 * 1024.0)
362 }
363
364 pub const fn from_giga(giga_bytes: usize) -> Self {
368 Self::new(giga_bytes, 1000usize.pow(3))
369 }
370 pub const fn from_giga_f64(giga_bytes: f64) -> Self {
374 Self::new_f64(giga_bytes, 1000.0 * 1000.0 * 1000.0)
375 }
376
377 pub const fn from_tebi(tebi_bytes: usize) -> Self {
381 Self::new(tebi_bytes, 1024usize.pow(4))
382 }
383 pub const fn from_tebi_f64(tebi_bytes: f64) -> Self {
387 Self::new_f64(tebi_bytes, 1024.0 * 1024.0 * 1024.0 * 1024.0)
388 }
389
390 pub const fn from_tera(tera_bytes: usize) -> Self {
394 Self::new(tera_bytes, 1000usize.pow(4))
395 }
396 pub const fn from_tera_f64(tera_bytes: f64) -> Self {
400 Self::new_f64(tera_bytes, 1000.0 * 1000.0 * 1000.0 * 1000.0)
401 }
402}
403
404impl ByteLength {
405 pub fn max(self, other: Self) -> Self {
407 Self(self.0.max(other.0))
408 }
409
410 pub fn min(self, other: Self) -> Self {
412 Self(self.0.min(other.0))
413 }
414}
415
416impl fmt::Debug for ByteLength {
417 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
418 if f.alternate() {
419 f.debug_tuple("ByteLength").field(&self.0).finish()
420 } else {
421 write!(f, "ByteLength({self})")
422 }
423 }
424}
425
426impl fmt::Display for ByteLength {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429 if f.alternate() {
430 if self.0 >= 1024usize.pow(4) {
431 write!(f, "{:.2}TiB", self.tebis())
432 } else if self.0 >= 1024usize.pow(3) {
433 write!(f, "{:.2}GiB", self.gibis())
434 } else if self.0 >= 1024usize.pow(2) {
435 write!(f, "{:.2}MiB", self.mebis())
436 } else if self.0 >= 1024 {
437 write!(f, "{:.2}KiB", self.kibis())
438 } else {
439 write!(f, "{}B", self.bytes())
440 }
441 } else if self.0 >= 1000usize.pow(4) {
442 write!(f, "{:.2}TB", self.teras())
443 } else if self.0 >= 1000usize.pow(3) {
444 write!(f, "{:.2}GB", self.gigas())
445 } else if self.0 >= 1000usize.pow(2) {
446 write!(f, "{:.2}MB", self.megas())
447 } else if self.0 >= 1000 {
448 write!(f, "{:.2}kB", self.kilos())
449 } else {
450 write!(f, "{}B", self.bytes())
451 }
452 }
453}
454impl std::str::FromStr for ByteLength {
456 type Err = std::num::ParseFloatError;
457
458 fn from_str(s: &str) -> Result<Self, Self::Err> {
459 if let Some(n) = s.strip_suffix("TiB") {
460 n.parse().map(ByteLength::from_tebi_f64)
461 } else if let Some(n) = s.strip_suffix("GiB") {
462 n.parse().map(ByteLength::from_gibi_f64)
463 } else if let Some(n) = s.strip_suffix("MiB") {
464 n.parse().map(ByteLength::from_mebi_f64)
465 } else if let Some(n) = s.strip_suffix("KiB") {
466 n.parse().map(ByteLength::from_kibi_f64)
467 } else if let Some(n) = s.strip_suffix("TB") {
468 n.parse().map(ByteLength::from_tera_f64)
469 } else if let Some(n) = s.strip_suffix("GB") {
470 n.parse().map(ByteLength::from_giga_f64)
471 } else if let Some(n) = s.strip_suffix("MB") {
472 n.parse().map(ByteLength::from_mega_f64)
473 } else if let Some(n) = s.strip_suffix("kB") {
474 n.parse().map(ByteLength::from_kilo_f64)
475 } else if let Some(n) = s.strip_suffix("B") {
476 n.parse().map(ByteLength::from_byte_f64)
477 } else {
478 s.parse().map(ByteLength::from_byte_f64)
479 }
480 }
481}
482impl<S: Into<Factor>> ops::Mul<S> for ByteLength {
483 type Output = Self;
484
485 fn mul(mut self, rhs: S) -> Self {
486 self.0 = (self.0 as f64 * rhs.into().0 as f64) as usize;
487 self
488 }
489}
490impl<S: Into<Factor>> ops::MulAssign<S> for ByteLength {
491 fn mul_assign(&mut self, rhs: S) {
492 *self = *self * rhs;
493 }
494}
495impl<S: Into<Factor>> ops::Div<S> for ByteLength {
496 type Output = Self;
497
498 fn div(mut self, rhs: S) -> Self {
499 self.0 = (self.0 as f64 / rhs.into().0 as f64) as usize;
500 self
501 }
502}
503impl<S: Into<Factor>> ops::DivAssign<S> for ByteLength {
504 fn div_assign(&mut self, rhs: S) {
505 *self = *self / rhs;
506 }
507}