]> git.proxmox.com Git - rustc.git/blame - vendor/bytesize/src/parse.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / bytesize / src / parse.rs
CommitLineData
49aad941
FG
1use super::ByteSize;
2
3impl std::str::FromStr for ByteSize {
4 type Err = String;
5
6 fn from_str(value: &str) -> Result<Self, Self::Err> {
7 if let Ok(v) = value.parse::<u64>() {
8 return Ok(Self(v));
9 }
781aab86 10 let number = take_while(value, |c| c.is_ascii_digit() || c == '.');
49aad941
FG
11 match number.parse::<f64>() {
12 Ok(v) => {
781aab86
FG
13 let suffix = skip_while(value, |c| {
14 c.is_whitespace() || c.is_ascii_digit() || c == '.'
15 });
49aad941
FG
16 match suffix.parse::<Unit>() {
17 Ok(u) => Ok(Self((v * u) as u64)),
18 Err(error) => Err(format!(
19 "couldn't parse {:?} into a known SI unit, {}",
20 suffix, error
21 )),
22 }
23 }
24 Err(error) => Err(format!(
25 "couldn't parse {:?} into a ByteSize, {}",
26 value, error
27 )),
28 }
29 }
30}
31
781aab86
FG
32fn take_while<P>(s: &str, mut predicate: P) -> &str
33where
34 P: FnMut(char) -> bool,
35{
36 let offset = s
37 .chars()
38 .take_while(|ch| predicate(*ch))
39 .map(|ch| ch.len_utf8())
40 .sum();
41 &s[..offset]
42}
43
44fn skip_while<P>(s: &str, mut predicate: P) -> &str
45where
46 P: FnMut(char) -> bool,
47{
48 let offset: usize = s
49 .chars()
50 .skip_while(|ch| predicate(*ch))
51 .map(|ch| ch.len_utf8())
52 .sum();
53 &s[(s.len() - offset)..]
54}
55
49aad941
FG
56enum Unit {
57 Byte,
58 // power of tens
59 KiloByte,
60 MegaByte,
61 GigaByte,
62 TeraByte,
63 PetaByte,
64 // power of twos
65 KibiByte,
66 MebiByte,
67 GibiByte,
68 TebiByte,
69 PebiByte,
70}
71
72impl Unit {
73 fn factor(&self) -> u64 {
74 match self {
75 Self::Byte => super::B,
76 // power of tens
77 Self::KiloByte => super::KB,
78 Self::MegaByte => super::MB,
79 Self::GigaByte => super::GB,
80 Self::TeraByte => super::TB,
81 Self::PetaByte => super::PB,
82 // power of twos
83 Self::KibiByte => super::KIB,
84 Self::MebiByte => super::MIB,
85 Self::GibiByte => super::GIB,
86 Self::TebiByte => super::TIB,
87 Self::PebiByte => super::PIB,
88 }
89 }
90}
91
92mod impl_ops {
93 use super::Unit;
94 use std::ops;
95
96 impl ops::Add<u64> for Unit {
97 type Output = u64;
98
99 fn add(self, other: u64) -> Self::Output {
100 self.factor() + other
101 }
102 }
103
104 impl ops::Add<Unit> for u64 {
105 type Output = u64;
106
107 fn add(self, other: Unit) -> Self::Output {
108 self + other.factor()
109 }
110 }
111
112 impl ops::Mul<u64> for Unit {
113 type Output = u64;
114
115 fn mul(self, other: u64) -> Self::Output {
116 self.factor() * other
117 }
118 }
119
120 impl ops::Mul<Unit> for u64 {
121 type Output = u64;
122
123 fn mul(self, other: Unit) -> Self::Output {
124 self * other.factor()
125 }
126 }
127
128 impl ops::Add<f64> for Unit {
129 type Output = f64;
130
131 fn add(self, other: f64) -> Self::Output {
132 self.factor() as f64 + other
133 }
134 }
135
136 impl ops::Add<Unit> for f64 {
137 type Output = f64;
138
139 fn add(self, other: Unit) -> Self::Output {
140 other.factor() as f64 + self
141 }
142 }
143
144 impl ops::Mul<f64> for Unit {
145 type Output = f64;
146
147 fn mul(self, other: f64) -> Self::Output {
148 self.factor() as f64 * other
149 }
150 }
151
152 impl ops::Mul<Unit> for f64 {
153 type Output = f64;
154
155 fn mul(self, other: Unit) -> Self::Output {
156 other.factor() as f64 * self
157 }
158 }
159}
160
161impl std::str::FromStr for Unit {
162 type Err = String;
163
164 fn from_str(unit: &str) -> Result<Self, Self::Err> {
165 match unit.to_lowercase().as_str() {
166 "b" => Ok(Self::Byte),
167 // power of tens
168 "k" | "kb" => Ok(Self::KiloByte),
169 "m" | "mb" => Ok(Self::MegaByte),
170 "g" | "gb" => Ok(Self::GigaByte),
171 "t" | "tb" => Ok(Self::TeraByte),
172 "p" | "pb" => Ok(Self::PetaByte),
173 // power of twos
174 "ki" | "kib" => Ok(Self::KibiByte),
175 "mi" | "mib" => Ok(Self::MebiByte),
176 "gi" | "gib" => Ok(Self::GibiByte),
177 "ti" | "tib" => Ok(Self::TebiByte),
178 "pi" | "pib" => Ok(Self::PebiByte),
179 _ => Err(format!("couldn't parse unit of {:?}", unit)),
180 }
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187
188 #[test]
189 fn when_ok() {
190 // shortcut for writing test cases
191 fn parse(s: &str) -> u64 {
192 s.parse::<ByteSize>().unwrap().0
193 }
194
195 assert_eq!("0".parse::<ByteSize>().unwrap().0, 0);
196 assert_eq!(parse("0"), 0);
197 assert_eq!(parse("500"), 500);
198 assert_eq!(parse("1K"), Unit::KiloByte * 1);
199 assert_eq!(parse("1Ki"), Unit::KibiByte * 1);
200 assert_eq!(parse("1.5Ki"), (1.5 * Unit::KibiByte) as u64);
201 assert_eq!(parse("1KiB"), 1 * Unit::KibiByte);
202 assert_eq!(parse("1.5KiB"), (1.5 * Unit::KibiByte) as u64);
203 assert_eq!(parse("3 MB"), Unit::MegaByte * 3);
204 assert_eq!(parse("4 MiB"), Unit::MebiByte * 4);
205 assert_eq!(parse("6 GB"), 6 * Unit::GigaByte);
206 assert_eq!(parse("4 GiB"), 4 * Unit::GibiByte);
207 assert_eq!(parse("88TB"), 88 * Unit::TeraByte);
208 assert_eq!(parse("521TiB"), 521 * Unit::TebiByte);
209 assert_eq!(parse("8 PB"), 8 * Unit::PetaByte);
210 assert_eq!(parse("8P"), 8 * Unit::PetaByte);
211 assert_eq!(parse("12 PiB"), 12 * Unit::PebiByte);
212 }
213
214 #[test]
215 fn when_err() {
216 // shortcut for writing test cases
217 fn parse(s: &str) -> Result<ByteSize, String> {
218 s.parse::<ByteSize>()
219 }
220
221 assert!(parse("").is_err());
222 assert!(parse("a124GB").is_err());
223 }
224
225 #[test]
226 fn to_and_from_str() {
227 // shortcut for writing test cases
228 fn parse(s: &str) -> u64 {
229 s.parse::<ByteSize>().unwrap().0
230 }
231
232 assert_eq!(parse(&format!("{}", parse("128GB"))), 128 * Unit::GigaByte);
233 assert_eq!(
234 parse(&crate::to_string(parse("128.000 GiB"), true)),
235 128 * Unit::GibiByte
236 );
237 }
238}