Skip to content

Instantly share code, notes, and snippets.

@juliusl
Created January 28, 2023 01:49
Show Gist options
  • Save juliusl/dc326001612dfa93f1d770e09f157ee7 to your computer and use it in GitHub Desktop.
Save juliusl/dc326001612dfa93f1d770e09f157ee7 to your computer and use it in GitHub Desktop.
Trait to match suffix of types that impl AsRef<str>
mod util {
impl<T> MatchSuffix for T where T: AsRef<str> {}
/// Trait for checking if self matches a specific suffix,
///
pub trait MatchSuffix
where
Self: AsRef<str>,
{
/// Returns true if `pat` is a suffix of self.as_ref::<str>() (.as_ref() implies this type in the rest of this doc),
///
/// Caveat: If the length of `pat` is less than .as_ref() this method returns false.
///
/// # Wildcard Syntax
/// The syntax for `pat` allows for wildcards, i.e. `.value.*`. A wildcard matches any non-whitespace character.
/// For example, if self.as_ref() returned "debug.value.test_value", and pat was `.value.*`, this would be considered a match.
/// Alternatively, if pat was `de*value.*` this would be considered a match.
///
/// Finally, if pat was `prod.value.*`, then it would not be considered a match.
///
/// A leading `*` is not required as this function is checking for a suffix match, howvever it is still supported.
///
/// To check for `*` in a pat, use `\*` to escape the wildcard symbol.
///
/// You can also check for length with wildcards. For example if pat is `*****`, and self.as_ref() is `abc` this would not be considered a match.
/// If self.as_ref() was instead `abcde` this would be considered a match. Be careful if using a leading * in this scenario because, in the context of this function a leading * implies that content is expected.
///
fn match_suffix(&self, pat: impl AsRef<str>) -> bool {
let content = self.as_ref();
if content.len() < pat.as_ref().len() {
return false;
}
let mut previous = 0;
let mut is_match = false;
let pat = pat.as_ref().replace(r#"\*"#, r#"()"#);
let content = content.replace("*", "()");
for part in pat.split("*") {
if let Some(pos) = content.find(part) {
if part.is_empty() {
is_match = content[previous..].len() + previous == content.len();
} else {
is_match = pos > previous;
previous = pos;
}
} else {
return false;
}
if !is_match {
return false;
}
}
is_match
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment