pub fn normalize(path: &str) -> String {
path.split('/')
.filter(|part| !part.is_empty())
.collect::<Vec<_>>()
.join("/")
}
pub fn has_prefix(path: &str, prefix: &str) -> bool {
strip_prefix(path, prefix).is_some()
}
pub fn strip_prefix<'a>(path: &'a str, prefix: &str) -> Option<&'a str> {
if prefix.is_empty() {
return Some(path);
}
let rest = path.strip_prefix(prefix)?;
match rest.as_bytes().first() {
None => Some(""),
Some(b'/') => Some(&rest[1..]),
Some(_) => None,
}
}
pub fn join(base: &str, other: &str) -> String {
match (base.is_empty(), other.is_empty()) {
(true, _) => other.to_string(),
(_, true) => base.to_string(),
_ => format!("{base}/{other}"),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normalize() {
assert_eq!(normalize(""), "");
assert_eq!(normalize("/"), "");
assert_eq!(normalize("foo"), "foo");
assert_eq!(normalize("/foo/bar/"), "foo/bar");
assert_eq!(normalize("//foo///bar//"), "foo/bar");
}
#[test]
fn test_has_prefix() {
assert!(has_prefix("foo/bar", ""));
assert!(has_prefix("foo/bar", "foo"));
assert!(has_prefix("foo/bar", "foo/bar"));
assert!(!has_prefix("foo/bar", "fo"));
assert!(!has_prefix("foobar", "foo"));
assert!(!has_prefix("foo", "foo/bar"));
}
#[test]
fn test_strip_prefix() {
assert_eq!(strip_prefix("foo/bar", ""), Some("foo/bar"));
assert_eq!(strip_prefix("foo/bar", "foo"), Some("bar"));
assert_eq!(strip_prefix("foo/bar", "foo/bar"), Some(""));
assert_eq!(strip_prefix("foobar", "foo"), None);
assert_eq!(strip_prefix("foo", "bar"), None);
}
#[test]
fn test_join() {
assert_eq!(join("", ""), "");
assert_eq!(join("foo", ""), "foo");
assert_eq!(join("", "bar"), "bar");
assert_eq!(join("foo", "bar"), "foo/bar");
}
}