1use super::num::Int;
17use std::fmt;
18use std::str::FromStr;
19use ParseError;
20
21const IBYTES: [u64; 7] = [1, 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50, 1 << 60];
22const BYTES: [u64; 7] = [
23 1,
24 1_000,
25 1_000_000,
26 1_000_000_000,
27 1_000_000_000_000,
28 1_000_000_000_000_000,
29 1_000_000_000_000_000_000,
30];
31
32#[derive(Debug, Copy, Clone, Eq, PartialEq)]
34pub enum Unit {
35 Byte,
37
38 KiByte,
40
41 MiByte,
43
44 GiByte,
46
47 TiByte,
49
50 PiByte,
52
53 EiByte,
55
56 KByte,
58
59 MByte,
61
62 GByte,
64
65 TByte,
67
68 PByte,
70
71 EByte,
73}
74
75impl Unit {
76 fn size<T: Int>(&self) -> Result<T, ParseError> {
77 let v = match self {
78 Unit::Byte => <T>::from_u64(1),
79 Unit::KiByte => <T>::from_u64(IBYTES[1]),
80 Unit::MiByte => <T>::from_u64(IBYTES[2]),
81 Unit::GiByte => <T>::from_u64(IBYTES[3]),
82 Unit::TiByte => <T>::from_u64(IBYTES[4]),
83 Unit::PiByte => <T>::from_u64(IBYTES[5]),
84 Unit::EiByte => <T>::from_u64(IBYTES[6]),
85 Unit::KByte => <T>::from_u64(BYTES[1]),
86 Unit::MByte => <T>::from_u64(BYTES[2]),
87 Unit::GByte => <T>::from_u64(BYTES[3]),
88 Unit::TByte => <T>::from_u64(BYTES[4]),
89 Unit::PByte => <T>::from_u64(BYTES[5]),
90 Unit::EByte => <T>::from_u64(BYTES[6]),
91 }.ok_or(ParseError::Overflow)?;
92
93 Ok(v)
94 }
95}
96
97impl fmt::Display for Unit {
98 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99 let unit = match self {
100 Unit::Byte => "B",
101 Unit::KiByte => "KiB",
102 Unit::MiByte => "MiB",
103 Unit::GiByte => "GiB",
104 Unit::TiByte => "TiB",
105 Unit::PiByte => "PiB",
106 Unit::EiByte => "EiB",
107 Unit::KByte => "KB",
108 Unit::MByte => "MB",
109 Unit::GByte => "GB",
110 Unit::TByte => "TB",
111 Unit::PByte => "PB",
112 Unit::EByte => "EB",
113 };
114
115 f.pad(unit)
116 }
117}
118
119impl FromStr for Unit {
120 type Err = ParseError;
121
122 fn from_str(s: &str) -> Result<Self, Self::Err> {
123 match s {
124 "" | "b" => Ok(Unit::Byte),
125 "ki" | "kib" => Ok(Unit::KiByte),
126 "mi" | "mib" => Ok(Unit::MiByte),
127 "gi" | "gib" => Ok(Unit::GiByte),
128 "ti" | "tib" => Ok(Unit::TiByte),
129 "pi" | "pib" => Ok(Unit::PiByte),
130 "ei" | "eib" => Ok(Unit::EiByte),
131 "k" | "kb" => Ok(Unit::KByte),
132 "m" | "mb" => Ok(Unit::MByte),
133 "g" | "gb" => Ok(Unit::GByte),
134 "t" | "tb" => Ok(Unit::TByte),
135 "p" | "pb" => Ok(Unit::PByte),
136 "e" | "eb" => Ok(Unit::EByte),
137 _ => Err(ParseError::InvalidUnit),
138 }
139 }
140}
141
142#[derive(Debug, Copy, Clone, Eq, PartialEq)]
146pub struct Bytes<T: Int = usize>(T);
147
148impl Bytes {
149 pub fn new<T: Int>(value: T, unit: Unit) -> Result<Bytes<T>, ParseError> {
162 let unit_size = unit.size::<T>()?;
163 let size = value.checked_mul(unit_size).ok_or(ParseError::Overflow)?;
164
165 Ok(Bytes(size))
166 }
167}
168
169impl<T: Int> Bytes<T> {
170 pub fn size(&self) -> T {
172 return self.0;
173 }
174}
175
176impl<T: Int> FromStr for Bytes<T> {
177 type Err = ParseError;
178
179 fn from_str(s: &str) -> Result<Self, Self::Err> {
180 let input = s.trim();
181 if input.is_empty() {
182 return Err(ParseError::EmptyInput);
183 }
184
185 let unit_index = input
186 .chars()
187 .position(|c| c.is_alphabetic() || c.is_whitespace())
188 .unwrap_or(input.len());
189
190 if unit_index == 0 {
191 return Err(ParseError::MissingValue);
192 }
193
194 let (vstr, ustr) = input.split_at(unit_index);
195 let unit = ustr.trim().to_lowercase().parse()?;
196 let value = vstr.parse::<T>().or(Err(ParseError::InvalidValue))?;
197
198 Bytes::new(value, unit)
199 }
200}
201
202#[cfg(test)]
203mod tests;