zng_unit/
byte.rs

1use std::{fmt, ops};
2
3use super::Factor;
4
5/// Extension methods for initializing [`ByteLength`] values.
6pub trait ByteUnits {
7    /// Bytes.
8    ///
9    /// See [`ByteLength`] for more details.
10    fn bytes(self) -> ByteLength;
11    /// Kibi-bytes.
12    ///
13    /// See [`ByteLength::from_kibi`] for more details.
14    fn kibibytes(self) -> ByteLength;
15    /// Kilo-bytes.
16    ///
17    /// See [`ByteLength::from_kilo`] for more details.
18    fn kilobytes(self) -> ByteLength;
19
20    /// Mebi-bytes.
21    ///
22    /// See [`ByteLength::from_mebi`] for more details.
23    fn mebibytes(self) -> ByteLength;
24    /// Mega-bytes.
25    ///
26    /// See [`ByteLength::from_mega`] for more details.
27    fn megabytes(self) -> ByteLength;
28
29    /// Gibi-bytes.
30    ///
31    /// See [`ByteLength::from_gibi`] for more details.
32    fn gibibytes(self) -> ByteLength;
33    /// Giga-bytes.
34    ///
35    /// See [`ByteLength::from_giga`] for more details.
36    fn gigabytes(self) -> ByteLength;
37
38    /// Tebi-bytes.
39    ///
40    /// See [`ByteLength::from_tebi`] for more details.
41    fn tebibytes(self) -> ByteLength;
42    /// Tera-bytes.
43    ///
44    /// See [`ByteLength::from_tera`] for more details.
45    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/// A length in bytes.
123///
124/// The value is stored in bytes, you can use associated functions to convert from other units or
125/// you can use the [`ByteUnits`] extension methods to initialize from an integer literal.
126#[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    /// Length in bytes.
160    ///
161    /// This is the same as `.0`.
162    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    /// Length in kibi-bytes.
171    pub fn kibis(self) -> f64 {
172        self.scaled(1024.0)
173    }
174
175    /// Length in kilo-bytes.
176    pub fn kilos(self) -> f64 {
177        self.scaled(1000.0)
178    }
179
180    /// Length in mebi-bytes.
181    pub fn mebis(self) -> f64 {
182        self.scaled(1024.0f64.powi(2))
183    }
184
185    /// Length in mega-bytes.
186    pub fn megas(self) -> f64 {
187        self.scaled(1000.0f64.powi(2))
188    }
189
190    /// Length in gibi-bytes.
191    pub fn gibis(self) -> f64 {
192        self.scaled(1024.0f64.powi(3))
193    }
194
195    /// Length in giga-bytes.
196    pub fn gigas(self) -> f64 {
197        self.scaled(1000.0f64.powi(3))
198    }
199
200    /// Length in tebi-bytes.
201    pub fn tebis(self) -> f64 {
202        self.scaled(1024.0f64.powi(4))
203    }
204
205    /// Length in tera-bytes.
206    pub fn teras(self) -> f64 {
207        self.scaled(1000.0f64.powi(4))
208    }
209
210    /// Maximum representable byte length.
211    pub const MAX: ByteLength = ByteLength(usize::MAX);
212
213    /// Adds the two lengths without overflowing or wrapping.
214    pub const fn saturating_add(self, rhs: ByteLength) -> ByteLength {
215        ByteLength(self.0.saturating_add(rhs.0))
216    }
217
218    /// Subtracts the two lengths without overflowing or wrapping.
219    pub const fn saturating_sub(self, rhs: ByteLength) -> ByteLength {
220        ByteLength(self.0.saturating_sub(rhs.0))
221    }
222
223    /// Multiplies the two lengths without overflowing or wrapping.
224    pub const fn saturating_mul(self, rhs: ByteLength) -> ByteLength {
225        ByteLength(self.0.saturating_mul(rhs.0))
226    }
227
228    // unstable
229    ///// Divides the two lengths without overflowing or wrapping.
230    //pub fn saturating_div(self, rhs: ByteLength) -> ByteLength {
231    //    ByteLength(self.0.saturating_div(rhs.0))
232    //}
233
234    /// Adds the two lengths wrapping overflows.
235    pub const fn wrapping_add(self, rhs: ByteLength) -> ByteLength {
236        ByteLength(self.0.wrapping_add(rhs.0))
237    }
238
239    /// Subtracts the two lengths wrapping overflows.
240    pub const fn wrapping_sub(self, rhs: ByteLength) -> ByteLength {
241        ByteLength(self.0.wrapping_sub(rhs.0))
242    }
243
244    /// Multiplies the two lengths wrapping overflows.
245    pub const fn wrapping_mul(self, rhs: ByteLength) -> ByteLength {
246        ByteLength(self.0.wrapping_mul(rhs.0))
247    }
248
249    /// Divides the two lengths wrapping overflows.
250    pub const fn wrapping_div(self, rhs: ByteLength) -> ByteLength {
251        ByteLength(self.0.wrapping_div(rhs.0))
252    }
253
254    /// Adds the two lengths, returns `None` if the sum overflows.
255    pub fn checked_add(self, rhs: ByteLength) -> Option<ByteLength> {
256        self.0.checked_add(rhs.0).map(ByteLength)
257    }
258
259    /// Subtracts the two lengths, returns `None` if the subtraction overflows.
260    pub fn checked_sub(self, rhs: ByteLength) -> Option<ByteLength> {
261        self.0.checked_sub(rhs.0).map(ByteLength)
262    }
263
264    /// Multiplies the two lengths, returns `None` if the sum overflows.
265    pub fn checked_mul(self, rhs: ByteLength) -> Option<ByteLength> {
266        self.0.checked_mul(rhs.0).map(ByteLength)
267    }
268
269    /// Divides the two lengths, returns `None` if the division overflows.
270    pub fn checked_div(self, rhs: ByteLength) -> Option<ByteLength> {
271        self.0.checked_div(rhs.0).map(ByteLength)
272    }
273}
274
275/// Constructors
276impl ByteLength {
277    /// From bytes.
278    ///
279    /// This is the same as `ByteLength(bytes)`.
280    pub const fn from_byte(bytes: usize) -> Self {
281        ByteLength(bytes)
282    }
283
284    /// From fractional bytes.
285    ///
286    /// Just rounds the value.
287    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    /// From kibi-bytes.
300    ///
301    /// 1 kibi-byte equals 1024 bytes.
302    pub const fn from_kibi(kibi_bytes: usize) -> Self {
303        Self::new(kibi_bytes, 1024)
304    }
305    /// From kibi-bytes.
306    ///
307    /// 1 kibi-byte equals 1024 bytes.
308    pub const fn from_kibi_f64(kibi_bytes: f64) -> Self {
309        Self::new_f64(kibi_bytes, 1024.0)
310    }
311
312    /// From kilo-bytes.
313    ///
314    /// 1 kilo-byte equals 1000 bytes.
315    pub const fn from_kilo(kilo_bytes: usize) -> Self {
316        Self::new(kilo_bytes, 1000)
317    }
318    /// From kilo-bytes.
319    ///
320    /// 1 kilo-byte equals 1000 bytes.
321    pub const fn from_kilo_f64(kilo_bytes: f64) -> Self {
322        Self::new_f64(kilo_bytes, 1000.0)
323    }
324
325    /// From mebi-bytes.
326    ///
327    /// 1 mebi-byte equals 1024² bytes.
328    pub const fn from_mebi(mebi_bytes: usize) -> Self {
329        Self::new(mebi_bytes, 1024usize.pow(2))
330    }
331    /// From mebi-bytes.
332    ///
333    /// 1 mebi-byte equals 1024² bytes.
334    pub const fn from_mebi_f64(mebi_bytes: f64) -> Self {
335        Self::new_f64(mebi_bytes, 1024.0 * 1024.0)
336    }
337
338    /// From mega-bytes.
339    ///
340    /// 1 mega-byte equals 1000² bytes.
341    pub const fn from_mega(mega_bytes: usize) -> Self {
342        Self::new(mega_bytes, 1000usize.pow(2))
343    }
344    /// From mega-bytes.
345    ///
346    /// 1 mega-byte equals 1000² bytes.
347    pub const fn from_mega_f64(mebi_bytes: f64) -> Self {
348        Self::new_f64(mebi_bytes, 1000.0 * 1000.0)
349    }
350
351    /// From gibi-bytes.
352    ///
353    /// 1 gibi-byte equals 1024³ bytes.
354    pub const fn from_gibi(gibi_bytes: usize) -> Self {
355        Self::new(gibi_bytes, 1024usize.pow(3))
356    }
357    /// From gibi-bytes.
358    ///
359    /// 1 gibi-byte equals 1024³ bytes.
360    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    /// From giga-bytes.
365    ///
366    /// 1 giga-byte equals 1000³ bytes.
367    pub const fn from_giga(giga_bytes: usize) -> Self {
368        Self::new(giga_bytes, 1000usize.pow(3))
369    }
370    /// From giga-bytes.
371    ///
372    /// 1 giga-byte equals 1000³ bytes.
373    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    /// From tebi-bytes.
378    ///
379    /// 1 tebi-byte equals 1024^4 bytes.
380    pub const fn from_tebi(tebi_bytes: usize) -> Self {
381        Self::new(tebi_bytes, 1024usize.pow(4))
382    }
383    /// From tebi-bytes.
384    ///
385    /// 1 tebi-byte equals 1024^4 bytes.
386    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    /// From tera-bytes.
391    ///
392    /// 1 tera-byte equals 1000^4 bytes.
393    pub const fn from_tera(tera_bytes: usize) -> Self {
394        Self::new(tera_bytes, 1000usize.pow(4))
395    }
396    /// From tera-bytes.
397    ///
398    /// 1 tera-byte equals 1000^4 bytes.
399    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    /// Compares and returns the maximum of two lengths.
406    pub fn max(self, other: Self) -> Self {
407        Self(self.0.max(other.0))
408    }
409
410    /// Compares and returns the minimum of two lengths.
411    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
426/// Alternative mode prints in binary units (kibi, mebi, gibi, tebi)
427impl 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}
454/// Parses `"##"`, `"##TiB"`, `"##GiB"`, `"##MiB"`, `"##KiB"`, `"##B"`, `"##TB"`, `"##GB"`, `"##MB"`, `"##kB"` and `"##B"` where `##` is an `usize`.
455impl 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}