pub(crate) fn matches(pattern: &str, s: &str) -> bool {
let mut piter = pattern.chars();
let mut siter = s.chars();
let mut pc = piter.next();
let mut sc = siter.next();
while pc.is_some() && sc.is_some() {
let pcurr = pc.unwrap();
let scurr = sc.unwrap();
if pcurr == '*' {
pc = piter.next();
if let Some(nc) = pc {
if nc == '*' {
continue;
}
let pnext = pc.unwrap();
while sc.is_some() && sc != Some(pnext) {
sc = siter.next();
}
} else {
return true;
}
} else if pcurr != scurr {
return false;
}
pc = piter.next();
sc = siter.next();
}
if pc.is_some() || sc.is_some() {
return false;
}
true
}
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;
#[test]
fn test_matches() {
let cases = vec![
("resources:blog:123", "resources:blog:123", true),
("re*123", "resources:blog:123", true),
("resources:blog:*", "resources:blog:123", true),
("resources:*", "resources:blog:123", true),
("resources:blog:123", "resources:blog:789", false),
("accounts:123", "resources:blog:789", false),
("actions:*:123", "actions:accounts:list:123", false),
("actions:*:list:*", "actions:accounts:list:123", true),
("actions:*:*:123", "actions:accounts:list:123", true),
("actions:**123", "actions:accounts:list:123", true),
];
for x in cases {
let (pattern, input, expected) = x;
let actual = matches(pattern, input);
assert_eq!(expected, actual, "pattern: {}, input: {}", pattern, input);
}
}
#[bench]
fn bench_match_wildcard(b: &mut Bencher) {
let pattern = "actions:*:list:123";
let input = "actions:accounts:list:123";
b.iter(|| matches(pattern, input));
}
#[bench]
fn bench_match_exact(b: &mut Bencher) {
let pattern = "actions:accounts:list:123";
let input = "actions:accounts:list:123";
b.iter(|| matches(pattern, input));
}
}