use std::num::IntErrorKind;
pub enum PrettyBufferSizeParseError {
Empty,
Zero,
InvalidFormat,
InvalidCharacters,
TooLarge,
}
pub fn parse_pretty_buffer_size(s: &str) -> Result<u32, PrettyBufferSizeParseError> {
let s = s.trim();
if s.is_empty() {
return Err(PrettyBufferSizeParseError::Empty);
}
let mut iter = s.chars();
let (s, radix) = match (iter.next(), iter.next().map(|c| c.to_ascii_lowercase())) {
(Some('0'), Some('x')) => (&s[2..], 16),
(Some('0'), Some('o')) => (&s[2..], 8),
(Some('0'), Some('b')) => (&s[2..], 2),
_ => (s, 10),
};
let mut iter = s.chars();
let (s, multiplier) = match iter.next_back().map(|c| c.to_ascii_lowercase()) {
Some('k') => (&s[..(s.len() - 1)], 1024),
Some('m') => (&s[..(s.len() - 1)], 1024 * 1024),
Some('g') => (&s[..(s.len() - 1)], 1024 * 1024 * 1024),
Some('b') => match iter.next_back().map(|c| c.to_ascii_lowercase()) {
Some('k') => (&s[..(s.len() - 2)], 1024),
Some('m') => (&s[..(s.len() - 2)], 1024 * 1024),
Some('g') => (&s[..(s.len() - 2)], 1024 * 1024 * 1024),
Some(_) if radix < 11 => (&s[..(s.len() - 1)], 1),
_ => (s, 1),
},
_ => (s, 1),
};
match s.chars().next() {
Some(c) if c.is_ascii_alphanumeric() => {}
_ => return Err(PrettyBufferSizeParseError::InvalidFormat),
}
let size = match u32::from_str_radix(s, radix) {
Ok(0) => return Err(PrettyBufferSizeParseError::Zero),
Ok(size) => size,
Err(parse_int_error) => {
return Err(match parse_int_error.kind() {
IntErrorKind::Empty => PrettyBufferSizeParseError::Empty,
IntErrorKind::PosOverflow => PrettyBufferSizeParseError::TooLarge,
_ => PrettyBufferSizeParseError::InvalidCharacters,
});
}
};
match size.checked_mul(multiplier) {
Some(size) => Ok(size),
None => Err(PrettyBufferSizeParseError::TooLarge),
}
}