pub fn last_name_from_path(path: &str) -> &str {
let after_slash = match path.rfind('/') {
Some(pos) => &path[pos + 1..],
None => path,
};
match after_slash.rfind('\\') {
Some(pos) => &after_slash[pos + 1..],
None => after_slash,
}
}
pub fn exe_name_match(exe_path: &str, name: &str) -> bool {
if let Some(rest) = exe_path.strip_prefix(name) {
rest.is_empty() || rest.starts_with('.')
} else {
false
}
}
pub fn read_u32_from_str(s: &str) -> Option<(u32, &str)> {
let bytes = s.as_bytes();
let mut i = 0usize;
if i >= bytes.len() || !bytes[i].is_ascii_digit() {
return None;
}
let mut result: u32 = 0;
while i < bytes.len() && bytes[i].is_ascii_digit() {
result = result
.wrapping_mul(10)
.wrapping_add((bytes[i] - b'0') as u32);
i += 1;
}
if i < bytes.len() {
match bytes[i] {
b'K' => {
result <<= 10;
i += 1;
if i < bytes.len() && bytes[i] == b'i' {
i += 1;
}
if i < bytes.len() && bytes[i] == b'B' {
i += 1;
}
}
b'M' => {
result <<= 20;
i += 1;
if i < bytes.len() && bytes[i] == b'i' {
i += 1;
}
if i < bytes.len() && bytes[i] == b'B' {
i += 1;
}
}
b'G' => {
result <<= 30;
i += 1;
if i < bytes.len() && bytes[i] == b'i' {
i += 1;
}
if i < bytes.len() && bytes[i] == b'B' {
i += 1;
}
}
_ => {}
}
}
Some((result, &s[i..]))
}
pub fn long_command_w_arg<'a>(arg: &'a str, prefix: &str) -> Option<&'a str> {
arg.strip_prefix(prefix)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_last_name_from_path_unix() {
assert_eq!(last_name_from_path("/a/b/c"), "c");
}
#[test]
fn test_last_name_from_path_windows() {
assert_eq!(last_name_from_path("a\\b"), "b");
}
#[test]
fn test_last_name_from_path_no_separator() {
assert_eq!(last_name_from_path("file.txt"), "file.txt");
}
#[test]
fn test_last_name_from_path_mixed() {
assert_eq!(last_name_from_path("a/b\\c"), "c");
}
#[test]
fn test_exe_name_match_exact() {
assert!(exe_name_match("lz4", "lz4"));
}
#[test]
fn test_exe_name_match_with_extension() {
assert!(exe_name_match("lz4.exe", "lz4"));
}
#[test]
fn test_exe_name_match_no_match() {
assert!(!exe_name_match("lz4cat", "lz4"));
}
#[test]
fn test_exe_name_match_prefix_only() {
assert!(!exe_name_match("lz4catx", "lz4cat"));
}
#[test]
fn test_read_u32_plain() {
assert_eq!(read_u32_from_str("42"), Some((42, "")));
}
#[test]
fn test_read_u32_k_suffix() {
assert_eq!(read_u32_from_str("64K"), Some((65536, "")));
}
#[test]
fn test_read_u32_kb_suffix() {
assert_eq!(read_u32_from_str("64KB"), Some((65536, "")));
}
#[test]
fn test_read_u32_kib_suffix() {
assert_eq!(read_u32_from_str("64KiB"), Some((65536, "")));
}
#[test]
fn test_read_u32_m_suffix() {
assert_eq!(read_u32_from_str("1M"), Some((1048576, "")));
}
#[test]
fn test_read_u32_mb_suffix() {
assert_eq!(read_u32_from_str("1MB"), Some((1048576, "")));
}
#[test]
fn test_read_u32_mib_suffix() {
assert_eq!(read_u32_from_str("1MiB"), Some((1048576, "")));
}
#[test]
fn test_read_u32_g_suffix() {
assert_eq!(read_u32_from_str("1G"), Some((1073741824, "")));
}
#[test]
fn test_read_u32_gb_suffix() {
assert_eq!(read_u32_from_str("1GB"), Some((1073741824, "")));
}
#[test]
fn test_read_u32_gib_suffix() {
assert_eq!(read_u32_from_str("1GiB"), Some((1073741824, "")));
}
#[test]
fn test_read_u32_empty() {
assert_eq!(read_u32_from_str(""), None);
}
#[test]
fn test_read_u32_no_digits() {
assert_eq!(read_u32_from_str("K"), None);
}
#[test]
fn test_read_u32_trailing_garbage() {
let (val, rest) = read_u32_from_str("12Mfoo").unwrap();
assert_eq!(val, 12582912);
assert_eq!(rest, "foo");
}
#[test]
fn test_read_u32_plain_with_remainder() {
let (val, rest) = read_u32_from_str("42xyz").unwrap();
assert_eq!(val, 42);
assert_eq!(rest, "xyz");
}
#[test]
fn test_long_command_w_arg_match() {
assert_eq!(
long_command_w_arg("--block-size=64K", "--block-size="),
Some("64K")
);
}
#[test]
fn test_long_command_w_arg_no_match() {
assert_eq!(long_command_w_arg("--level=5", "--block-size="), None);
}
#[test]
fn test_long_command_w_arg_exact() {
assert_eq!(long_command_w_arg("--fast", "--fast"), Some(""));
}
}