pub trait PathPattern {
#[doc(alias = "IsSupportedBy")]
#[must_use]
fn is_supported_by<I, S>(&self, patterns: I) -> bool
where
I: IntoIterator<Item = S>,
S: AsRef<str>;
#[doc(alias = "IsAPathMatchWith")]
#[must_use]
fn is_a_path_match_with(&self, path: &str) -> bool;
}
impl PathPattern for str {
fn is_supported_by<I, S>(&self, patterns: I) -> bool
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
patterns
.into_iter()
.any(|pattern| pattern.as_ref().is_a_path_match_with(self))
}
fn is_a_path_match_with(&self, path: &str) -> bool {
if !self.as_bytes().contains(&b'*') {
return self == path;
}
segments_match(self.as_bytes(), path.as_bytes())
}
}
fn segments_match(mut pattern: &[u8], mut path: &[u8]) -> bool {
loop {
let (pattern_segment, pattern_rest) = split_segment(pattern);
let (path_segment, path_rest) = split_segment(path);
if pattern_segment != b"*" && pattern_segment != path_segment {
return false;
}
match (pattern_rest, path_rest) {
(None, None) => return true,
(Some(pattern_rest), Some(path_rest)) => {
pattern = pattern_rest;
path = path_rest;
}
_ => return false,
}
}
}
fn split_segment(input: &[u8]) -> (&[u8], Option<&[u8]>) {
match input.iter().position(|&byte| byte == b'.') {
Some(index) => (&input[..index], Some(&input[index + 1..])),
None => (input, None),
}
}