#[allow(dead_code)]
pub fn is_simple_match<P, N>(pattern: P, name: N) -> bool
where
P: AsRef<str>,
N: AsRef<str>,
{
inner_match(pattern, name, true)
}
pub fn is_match<P, N>(pattern: P, name: N) -> bool
where
P: AsRef<str>,
N: AsRef<str>,
{
inner_match(pattern, name, false)
}
#[allow(dead_code)]
pub fn is_match_as_pattern_prefix<P, N>(pattern: P, text: N) -> bool
where
P: AsRef<str>,
N: AsRef<str>,
{
let (mut p, mut t) = (pattern.as_ref().as_bytes().iter(), text.as_ref().as_bytes().iter());
while let (Some(&x), Some(&y)) = (p.next(), t.next()) {
if x == b'*' {
return true;
}
if x == b'?' {
continue;
}
if x != y {
return false;
}
}
text.as_ref().len() <= pattern.as_ref().len()
}
#[inline]
fn inner_match(pattern: impl AsRef<str>, name: impl AsRef<str>, simple: bool) -> bool {
let (pattern, name) = (pattern.as_ref(), name.as_ref());
if pattern.is_empty() {
return pattern == name;
}
if pattern == "*" {
return true;
}
deep_match(pattern.as_bytes(), name.as_bytes(), simple)
}
fn deep_match(mut pattern: &[u8], mut name: &[u8], simple: bool) -> bool {
while !pattern.is_empty() {
match pattern[0] {
b'?' => {
if name.is_empty() {
return simple;
}
}
b'*' => {
return pattern.len() == 1
|| deep_match(&pattern[1..], name, simple)
|| (!name.is_empty() && deep_match(pattern, &name[1..], simple));
}
_ => {
if name.is_empty() || name[0] != pattern[0] {
return false;
}
}
}
name = &name[1..];
pattern = &pattern[1..];
}
name.is_empty() && pattern.is_empty()
}
#[cfg(test)]
mod tests {
use super::{is_match, is_match_as_pattern_prefix, is_simple_match};
#[test_case::test_case("*", "s3:GetObject" => true ; "1")]
#[test_case::test_case("", "s3:GetObject" => false ; "2")]
#[test_case::test_case("", "" => true; "3")]
#[test_case::test_case("s3:*", "s3:ListMultipartUploadParts" => true; "4")]
#[test_case::test_case("s3:ListBucketMultipartUploads", "s3:ListBucket" => false; "5")]
#[test_case::test_case("s3:ListBucket", "s3:ListBucket" => true; "6")]
#[test_case::test_case("s3:ListBucketMultipartUploads", "s3:ListBucketMultipartUploads" => true; "7")]
#[test_case::test_case("my-bucket/oo*", "my-bucket/oo" => true; "8")]
#[test_case::test_case("my-bucket/In*", "my-bucket/India/Karnataka/" => true; "9")]
#[test_case::test_case("my-bucket/In*", "my-bucket/Karnataka/India/" => false; "10")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban", "my-bucket/India/Karnataka/Ban" => true; "11")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban", "my-bucket/India/Karnataka/Ban/Ban/Ban/Ban/Ban" => true; "12")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban", "my-bucket/India/Karnataka/Area1/Area2/Area3/Ban" => true; "13")]
#[test_case::test_case( "my-bucket/In*/Ka*/Ba", "my-bucket/India/State1/State2/Karnataka/Area1/Area2/Area3/Ban" => ignore["will fail"] true; "14")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban", "my-bucket/India/Karnataka/Bangalore" => false; "15")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban*", "my-bucket/India/Karnataka/Bangalore" => true; "16")]
#[test_case::test_case("my-bucket/*", "my-bucket/India" => true; "17")]
#[test_case::test_case("my-bucket/oo*", "my-bucket/odo" => false; "18")]
#[test_case::test_case("my-bucket?/abc*", "mybucket/abc" => false; "19")]
#[test_case::test_case("my-bucket?/abc*", "my-bucket1/abc" => true; "20")]
#[test_case::test_case("my-?-bucket/abc*", "my--bucket/abc" => false; "21")]
#[test_case::test_case("my-?-bucket/abc*", "my-1-bucket/abc" => true; "22")]
#[test_case::test_case("my-?-bucket/abc*", "my-k-bucket/abc" => true; "23")]
#[test_case::test_case("my??bucket/abc*", "mybucket/abc" => false; "24")]
#[test_case::test_case("my??bucket/abc*", "my4abucket/abc" => true; "25")]
#[test_case::test_case("my-bucket?abc*", "my-bucket/abc" => true; "26")]
#[test_case::test_case("my-bucket/abc?efg", "my-bucket/abcdefg" => true; "27")]
#[test_case::test_case("my-bucket/abc?efg", "my-bucket/abc/efg" => true; "28")]
#[test_case::test_case("my-bucket/abc????", "my-bucket/abcde" => false; "29")]
#[test_case::test_case("my-bucket/abc????", "my-bucket/abcdefg" => true; "30")]
#[test_case::test_case("my-bucket/abc?", "my-bucket/abc" => false; "31")]
#[test_case::test_case("my-bucket/abc?", "my-bucket/abcd" => true; "32")]
#[test_case::test_case("my-bucket/abc?", "my-bucket/abcde" => false; "33")]
#[test_case::test_case("my-bucket/mnop*?", "my-bucket/mnop" => false; "34")]
#[test_case::test_case("my-bucket/mnop*?", "my-bucket/mnopqrst/mnopqr" => true; "35")]
#[test_case::test_case("my-bucket/mnop*?", "my-bucket/mnopqrst/mnopqrs" => true; "36")]
#[test_case::test_case("my-bucket/mnop*?", "my-bucket/mnop" => false; "37")]
#[test_case::test_case("my-bucket/mnop*?", "my-bucket/mnopq" => true; "38")]
#[test_case::test_case("my-bucket/mnop*?", "my-bucket/mnopqr" => true; "39")]
#[test_case::test_case("my-bucket/mnop*?and", "my-bucket/mnopqand" => true; "40")]
#[test_case::test_case("my-bucket/mnop*?and", "my-bucket/mnopand" => false; "41")]
#[test_case::test_case("my-bucket/mnop*?and", "my-bucket/mnopqand" => true; "42")]
#[test_case::test_case("my-bucket/mnop*?", "my-bucket/mn" => false; "43")]
#[test_case::test_case("my-bucket/mnop*?", "my-bucket/mnopqrst/mnopqrs" => true; "44")]
#[test_case::test_case("my-bucket/mnop*??", "my-bucket/mnopqrst" => true; "45")]
#[test_case::test_case("my-bucket/mnop*qrst", "my-bucket/mnopabcdegqrst" => true; "46")]
#[test_case::test_case("my-bucket/mnop*?and", "my-bucket/mnopqand" => true; "47")]
#[test_case::test_case("my-bucket/mnop*?and", "my-bucket/mnopand" => false; "48")]
#[test_case::test_case("my-bucket/mnop*?and?", "my-bucket/mnopqanda" => true; "49")]
#[test_case::test_case("my-bucket/mnop*?and", "my-bucket/mnopqanda" => false; "50")]
#[test_case::test_case("my-?-bucket/abc*", "my-bucket/mnopqanda" => false; "51")]
#[test_case::test_case("a?", "a" => false; "52")]
#[test_case::test_case("*", "mybucket/myobject" => true; "53")]
fn test_is_match(pattern: &str, text: &str) -> bool {
is_match(pattern, text)
}
#[test_case::test_case("*", "s3:GetObject" => true ; "1")]
#[test_case::test_case("", "s3:GetObject" => false ; "2")]
#[test_case::test_case("", "" => true ; "3")]
#[test_case::test_case("s3:*", "s3:ListMultipartUploadParts" => true ; "4")]
#[test_case::test_case("s3:ListBucketMultipartUploads", "s3:ListBucket" => false ; "5")]
#[test_case::test_case("s3:ListBucket", "s3:ListBucket" => true ; "6")]
#[test_case::test_case("s3:ListBucketMultipartUploads", "s3:ListBucketMultipartUploads" => true ; "7")]
#[test_case::test_case("my-bucket/oo*", "my-bucket/oo" => true ; "8")]
#[test_case::test_case("my-bucket/In*", "my-bucket/India/Karnataka/" => true ; "9")]
#[test_case::test_case("my-bucket/In*", "my-bucket/Karnataka/India/" => false ; "10")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban", "my-bucket/India/Karnataka/Ban" => true ; "11")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban", "my-bucket/India/Karnataka/Ban/Ban/Ban/Ban/Ban" => true ; "12")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban", "my-bucket/India/Karnataka/Area1/Area2/Area3/Ban" => true ; "13")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban", "my-bucket/India/State1/State2/Karnataka/Area1/Area2/Area3/Ban" => true ; "14")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban", "my-bucket/India/Karnataka/Bangalore" => false ; "15")]
#[test_case::test_case("my-bucket/In*/Ka*/Ban*", "my-bucket/India/Karnataka/Bangalore" => true ; "16")]
#[test_case::test_case("my-bucket/*", "my-bucket/India" => true ; "17")]
#[test_case::test_case("my-bucket/oo*", "my-bucket/odo" => false ; "18")]
#[test_case::test_case("my-bucket/oo?*", "my-bucket/oo???" => true ; "19")]
#[test_case::test_case("my-bucket/oo??*", "my-bucket/odo" => false ; "20")]
#[test_case::test_case("?h?*", "?h?hello" => true ; "21")]
#[test_case::test_case("a?", "a" => true ; "22")]
fn test_is_simple_match(pattern: &str, text: &str) -> bool {
is_simple_match(pattern, text)
}
#[test_case::test_case("", "" => true ; "1")]
#[test_case::test_case("a", "" => true ; "2")]
#[test_case::test_case("a", "b" => false ; "3")]
#[test_case::test_case("abc", "ab" => true ; "4")]
#[test_case::test_case("ab*", "ab" => true ; "5")]
#[test_case::test_case("abc*", "ab" => true ; "6")]
#[test_case::test_case("abc?", "ab" => true ; "7")]
#[test_case::test_case("abc*", "abd" => false ; "8")]
#[test_case::test_case("abc*c", "abcd" => true ; "9")]
#[test_case::test_case("ab*??d", "abxxc" => true ; "10")]
#[test_case::test_case("ab*??", "abxc" => true ; "11")]
#[test_case::test_case("ab??", "abxc" => true ; "12")]
#[test_case::test_case("ab??", "abx" => true ; "13")]
#[test_case::test_case("ab??d", "abcxd" => true ; "14")]
#[test_case::test_case("ab??d", "abcxdd" => false ; "15")]
#[test_case::test_case("", "b" => false ; "16")]
fn test_is_match_as_pattern_prefix(pattern: &str, text: &str) -> bool {
is_match_as_pattern_prefix(pattern, text)
}
}