use regex::Regex;
pub fn parse_block_size(s: &str) -> Result<usize, &'static str> {
let block_size_regex = Regex::new(r"^(?i)(\d+) *((k|m)b?)?$").unwrap();
let captures = block_size_regex.captures(s);
match captures {
Some(groups) => {
let units = groups[1].parse::<usize>().map_err(|_x| "Not a number.")?;
let unit_size = match groups.get(3).map(|m| m.as_str().to_uppercase()) {
Some(ref u) if u == "K" => 1024,
Some(ref u) if u == "M" => 1024 * 1024,
_ => 1
};
let bytes_length = (units * unit_size) as usize;
if bytes_length & (bytes_length - 1) == 0 {
Ok((units * unit_size) as usize)
} else {
Err("Should be a power of two.")
}
},
_ => {
Err("Use a number of bytes with optional scale (e.g. 4096, 128k or 2M).")
}
}
}
#[cfg(test)]
mod test {
use super::*;
use assert_matches::*;
#[test]
fn test_block_size_parser_good() {
let k128 = 128 * 1024;
let m2 = 2 * 1024 * 1024;
assert_eq!(parse_block_size("4096"), Ok(4096));
assert_eq!(parse_block_size("128k"), Ok(k128));
assert_eq!(parse_block_size("128K"), Ok(k128));
assert_eq!(parse_block_size("2m"), Ok(m2));
assert_eq!(parse_block_size("2M"), Ok(m2));
}
#[test]
fn test_block_size_parser_bad() {
assert_matches!(parse_block_size(""), Err(_));
assert_matches!(parse_block_size("xxx"), Err(_));
assert_matches!(parse_block_size("-128k"), Err(_));
assert_matches!(parse_block_size("4096.000"), Err(_));
assert_matches!(parse_block_size("4095"), Err(_));
}
}