1pub fn parse_decimal_number(input: &str) -> Result<usize, String> {
9 let input = input.trim();
10 if input.is_empty() {
11 return Err("empty input".to_string());
12 }
13
14 let (digits, multiplier) = match input.as_bytes().last() {
15 Some(b'k' | b'K') => (&input[..input.len() - 1], 1_000usize),
16 Some(b'M') => (&input[..input.len() - 1], 1_000_000),
17 Some(b'G') => (&input[..input.len() - 1], 1_000_000_000),
18 _ => (input, 1),
19 };
20
21 let base: usize = digits
22 .parse()
23 .map_err(|_| format!("invalid number: '{input}'"))?;
24
25 base.checked_mul(multiplier)
26 .ok_or_else(|| format!("number too large: '{input}'"))
27}
28
29pub fn parse_binary_number(input: &str) -> Result<u64, String> {
37 let input = input.trim();
38 if input.is_empty() {
39 return Err("empty input".to_string());
40 }
41
42 let (digits, multiplier) = match input.as_bytes().last() {
43 Some(b'k' | b'K') => (&input[..input.len() - 1], 1_024u64),
44 Some(b'M') => (&input[..input.len() - 1], 1_048_576),
45 Some(b'G') => (&input[..input.len() - 1], 1_073_741_824),
46 _ => (input, 1),
47 };
48
49 let base: u64 = digits
50 .parse()
51 .map_err(|_| format!("invalid number: '{input}'"))?;
52
53 base.checked_mul(multiplier)
54 .ok_or_else(|| format!("number too large: '{input}'"))
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
64 fn decimal_plain_number() {
65 assert_eq!(parse_decimal_number("10000").unwrap(), 10_000);
66 }
67
68 #[test]
69 fn decimal_zero() {
70 assert_eq!(parse_decimal_number("0").unwrap(), 0);
71 }
72
73 #[test]
74 fn decimal_suffix_k_lower() {
75 assert_eq!(parse_decimal_number("10k").unwrap(), 10_000);
76 }
77
78 #[test]
79 fn decimal_suffix_k_upper() {
80 assert_eq!(parse_decimal_number("10K").unwrap(), 10_000);
81 }
82
83 #[test]
84 fn decimal_suffix_m() {
85 assert_eq!(parse_decimal_number("5M").unwrap(), 5_000_000);
86 }
87
88 #[test]
89 fn decimal_suffix_g() {
90 assert_eq!(parse_decimal_number("2G").unwrap(), 2_000_000_000);
91 }
92
93 #[test]
94 fn decimal_one_k() {
95 assert_eq!(parse_decimal_number("1k").unwrap(), 1_000);
96 }
97
98 #[test]
99 fn decimal_100k() {
100 assert_eq!(parse_decimal_number("100K").unwrap(), 100_000);
101 }
102
103 #[test]
104 fn decimal_whitespace_trimmed() {
105 assert_eq!(parse_decimal_number(" 8k ").unwrap(), 8_000);
106 }
107
108 #[test]
109 fn decimal_invalid_letters() {
110 assert!(parse_decimal_number("abc").is_err());
111 }
112
113 #[test]
114 fn decimal_invalid_decimal_point() {
115 assert!(parse_decimal_number("1.5k").is_err());
116 }
117
118 #[test]
119 fn decimal_empty_input() {
120 assert!(parse_decimal_number("").is_err());
121 }
122
123 #[test]
124 fn decimal_suffix_only() {
125 assert!(parse_decimal_number("k").is_err());
126 }
127
128 #[test]
129 fn decimal_negative() {
130 assert!(parse_decimal_number("-1k").is_err());
131 }
132
133 #[test]
134 fn decimal_overflow() {
135 let huge = format!("{}k", usize::MAX);
137 assert!(parse_decimal_number(&huge).is_err());
138 }
139
140 #[test]
143 fn binary_plain_number() {
144 assert_eq!(parse_binary_number("1048576").unwrap(), 1_048_576);
145 }
146
147 #[test]
148 fn binary_zero() {
149 assert_eq!(parse_binary_number("0").unwrap(), 0);
150 }
151
152 #[test]
153 fn binary_suffix_k_lower() {
154 assert_eq!(parse_binary_number("1k").unwrap(), 1_024);
155 }
156
157 #[test]
158 fn binary_suffix_k_upper() {
159 assert_eq!(parse_binary_number("10K").unwrap(), 10_240);
160 }
161
162 #[test]
163 fn binary_suffix_m() {
164 assert_eq!(parse_binary_number("1M").unwrap(), 1_048_576);
165 }
166
167 #[test]
168 fn binary_suffix_m_10() {
169 assert_eq!(parse_binary_number("10M").unwrap(), 10_485_760);
170 }
171
172 #[test]
173 fn binary_suffix_g() {
174 assert_eq!(parse_binary_number("1G").unwrap(), 1_073_741_824);
175 }
176
177 #[test]
178 fn binary_whitespace_trimmed() {
179 assert_eq!(parse_binary_number(" 5M ").unwrap(), 5_242_880);
180 }
181
182 #[test]
183 fn binary_invalid_letters() {
184 assert!(parse_binary_number("xyz").is_err());
185 }
186
187 #[test]
188 fn binary_invalid_decimal_point() {
189 assert!(parse_binary_number("1.5M").is_err());
190 }
191
192 #[test]
193 fn binary_empty_input() {
194 assert!(parse_binary_number("").is_err());
195 }
196
197 #[test]
198 fn binary_suffix_only() {
199 assert!(parse_binary_number("M").is_err());
200 }
201
202 #[test]
203 fn binary_overflow() {
204 let huge = format!("{}G", u64::MAX);
205 assert!(parse_binary_number(&huge).is_err());
206 }
207}