kutil_std/metric/
byte_count.rs

1use super::{super::string::*, units::*};
2
3use std::{fmt, num::*, str::*};
4
5//
6// ByteCount
7//
8
9/// Parsed byte count.
10#[derive(Clone, Copy, Debug, Default)]
11pub struct ByteCount(pub u64);
12
13impl ByteCount {
14    /// Constructor.
15    pub fn from_bytes(bytes: u64) -> Self {
16        Self(bytes)
17    }
18
19    /// Constructor.
20    pub fn from_kibibytes(kibibytes: u64) -> Self {
21        Self(kibibytes * KIBI)
22    }
23
24    /// Constructor.
25    pub fn from_mebibytes(mebibytes: u64) -> Self {
26        Self(mebibytes * MEBI)
27    }
28
29    /// Constructor.
30    pub fn from_gibibytes(gibibytes: u64) -> Self {
31        Self(gibibytes * GIBI)
32    }
33
34    /// Constructor.
35    pub fn from_tebibytes(tebibytes: u64) -> Self {
36        Self(tebibytes * TEBI)
37    }
38
39    fn split(representation: &str) -> Option<(&str, &str)> {
40        for (index, c) in representation.char_indices().rev() {
41            if c == ' ' {
42                return Some((&representation[..index], &representation[index + 1..]));
43            }
44
45            if c.is_ascii_digit() {
46                let index = index + 1;
47                return Some((&representation[..index], &representation[index..]));
48            }
49        }
50
51        None
52    }
53}
54
55impl From<u64> for ByteCount {
56    fn from(bytes: u64) -> Self {
57        Self(bytes)
58    }
59}
60
61impl Into<u64> for ByteCount {
62    fn into(self) -> u64 {
63        self.0
64    }
65}
66
67impl Into<usize> for ByteCount {
68    fn into(self) -> usize {
69        // TODO: casting errors
70        self.0 as usize
71    }
72}
73
74impl FromStr for ByteCount {
75    type Err = ParseError;
76
77    fn from_str(representation: &str) -> Result<Self, Self::Err> {
78        match Self::split(representation) {
79            Some((number, unit)) => {
80                let unit = parse_metric_unit(unit)?;
81
82                let integer: Result<u64, _> = number.parse();
83                match integer {
84                    Ok(integer) => Ok(Self(integer * unit)),
85
86                    Err(_) => {
87                        let float: f64 = number.parse().map_err(|error: ParseFloatError| error.to_string())?;
88
89                        if float >= 0.0 {
90                            // TODO: casting errors
91                            let unit = unit as f64;
92                            Ok(Self((float * unit).round() as u64))
93                        } else {
94                            Err("cannot be negative".into())
95                        }
96                    }
97                }
98            }
99
100            None => Ok(Self(representation.parse().map_err(|error: ParseIntError| error.to_string())?)),
101        }
102    }
103}
104
105impl fmt::Display for ByteCount {
106    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
107        write!(formatter, "{} bytes", self.0)
108    }
109}