use crate::Path;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum PathPattern {
Exact(Path),
Prefix(Path),
PrefixSuffix(Path, Path),
}
impl PathPattern {
pub fn exact(path: Path) -> Self {
PathPattern::Exact(path)
}
pub fn prefix(path: Path) -> Self {
PathPattern::Prefix(path)
}
pub fn prefix_suffix(prefix: Path, suffix: Path) -> Self {
PathPattern::PrefixSuffix(prefix, suffix)
}
pub fn matches(&self, path: &Path) -> bool {
match self {
PathPattern::Exact(p) => p == path,
PathPattern::Prefix(prefix) => path.has_prefix(prefix),
PathPattern::PrefixSuffix(prefix, suffix) => match path.strip_prefix(prefix) {
Some(rest) => {
rest.len() >= suffix.len()
&& rest.slice(rest.len() - suffix.len(), rest.len()) == *suffix
}
None => false,
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::path;
#[test]
fn exact_matches_only_itself() {
let p = PathPattern::exact(path!("a/b"));
assert!(p.matches(&path!("a/b")));
assert!(!p.matches(&path!("a")));
assert!(!p.matches(&path!("a/b/c")));
}
#[test]
fn prefix_is_component_wise() {
let p = PathPattern::prefix(path!("gate/api_key"));
assert!(p.matches(&path!("gate/api_key")));
assert!(p.matches(&path!("gate/api_key/inner")));
assert!(!p.matches(&path!("gate/api_key_other")));
}
#[test]
fn empty_prefix_matches_everything() {
let p = PathPattern::prefix(path!(""));
assert!(p.matches(&path!("")));
assert!(p.matches(&path!("anything/at/all")));
}
#[test]
fn prefix_suffix_middle_may_be_empty() {
let p = PathPattern::prefix_suffix(path!("accounts"), path!("provider"));
assert!(p.matches(&path!("accounts/provider")));
assert!(p.matches(&path!("accounts/personal/provider")));
assert!(p.matches(&path!("accounts/a/b/provider")));
assert!(!p.matches(&path!("accounts")));
assert!(!p.matches(&path!("accounts/personal/model")));
assert!(!p.matches(&path!("other/personal/provider")));
}
#[test]
fn prefix_suffix_component_wise() {
let p = PathPattern::prefix_suffix(path!("a"), path!("key"));
assert!(!p.matches(&path!("a/x/key_other")));
assert!(p.matches(&path!("a/x/key")));
}
}