use crate::error::Error;
pub fn parse_size(input: &str) -> Result<u64, Error> {
let input = input.trim();
if input.is_empty() {
return Err(Error::InvalidSize(input.to_owned()));
}
let s = input
.strip_suffix('B')
.or_else(|| input.strip_suffix('b'))
.unwrap_or(input);
let split_pos = s.find(|c: char| !c.is_ascii_digit()).unwrap_or(s.len());
let num_str = &s[..split_pos];
let suffix = &s[split_pos..];
if num_str.is_empty() {
return Err(Error::InvalidSize(input.to_owned()));
}
let base: u64 = num_str
.parse()
.map_err(|_| Error::InvalidSize(input.to_owned()))?;
let multiplier: u64 = match suffix.to_ascii_uppercase().as_str() {
"" => 1,
"K" | "KI" => 1024,
"M" | "MI" => 1024 * 1024,
"G" | "GI" => 1024 * 1024 * 1024,
"T" | "TI" => 1024 * 1024 * 1024 * 1024,
_ => {
return Err(Error::InvalidSize(input.to_owned()));
},
};
base.checked_mul(multiplier)
.ok_or_else(|| Error::InvalidSize(input.to_owned()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_plain_bytes() {
assert_eq!(parse_size("100").unwrap(), 100);
assert_eq!(parse_size("0").unwrap(), 0);
assert_eq!(parse_size("1").unwrap(), 1);
}
#[test]
fn test_kilobytes() {
assert_eq!(parse_size("1K").unwrap(), 1024);
assert_eq!(parse_size("100K").unwrap(), 102_400);
assert_eq!(parse_size("1KB").unwrap(), 1024);
assert_eq!(parse_size("1k").unwrap(), 1024);
assert_eq!(parse_size("1kb").unwrap(), 1024);
}
#[test]
fn test_megabytes() {
assert_eq!(parse_size("1M").unwrap(), 1024 * 1024);
assert_eq!(parse_size("100M").unwrap(), 100 * 1024 * 1024);
assert_eq!(parse_size("1MB").unwrap(), 1024 * 1024);
assert_eq!(parse_size("1m").unwrap(), 1024 * 1024);
}
#[test]
fn test_gigabytes() {
assert_eq!(parse_size("1G").unwrap(), 1024 * 1024 * 1024);
assert_eq!(parse_size("1GB").unwrap(), 1024 * 1024 * 1024);
assert_eq!(parse_size("2g").unwrap(), 2 * 1024 * 1024 * 1024);
}
#[test]
fn test_terabytes() {
assert_eq!(parse_size("1T").unwrap(), 1024 * 1024 * 1024 * 1024);
assert_eq!(parse_size("1TB").unwrap(), 1024 * 1024 * 1024 * 1024);
}
#[test]
fn test_whitespace_trimmed() {
assert_eq!(parse_size(" 100M ").unwrap(), 100 * 1024 * 1024);
}
#[test]
fn test_empty_string_error() {
assert!(parse_size("").is_err());
assert!(parse_size(" ").is_err());
}
#[test]
fn test_invalid_suffix_error() {
assert!(parse_size("100X").is_err());
assert!(parse_size("100Z").is_err());
assert!(parse_size("abc").is_err());
}
#[test]
fn test_overflow_error() {
assert!(parse_size("99999999999999T").is_err());
}
#[test]
fn test_suffix_only_error() {
assert!(parse_size("M").is_err());
assert!(parse_size("KB").is_err());
}
}