use super::AsStr;
use crate::error::Error;
pub fn apply<T: Pattern, M: Matcher>(v: &T, (pat,): (&M,)) -> Result<(), Error> {
if !v.validate_pattern(pat) {
return Err(Error::new(format!(
"does not match pattern /{}/",
pat.as_str()
)));
}
Ok(())
}
pub trait Matcher: AsStr {
fn is_match(&self, haystack: &str) -> bool;
}
pub trait Pattern {
fn validate_pattern<M: Matcher>(&self, matcher: &M) -> bool;
}
impl<T: AsStr> Pattern for T {
fn validate_pattern<M: Matcher>(&self, matcher: &M) -> bool {
matcher.is_match(self.as_str())
}
}
impl<T: Pattern> Pattern for Option<T> {
fn validate_pattern<M: Matcher>(&self, matcher: &M) -> bool {
match self {
Some(value) => value.validate_pattern(matcher),
None => true,
}
}
}
#[cfg(feature = "regex")]
#[doc(hidden)]
pub mod regex {
pub use ::regex::Regex;
use super::*;
impl Matcher for Regex {
fn is_match(&self, haystack: &str) -> bool {
self.is_match(haystack)
}
}
impl<T: Matcher> Matcher for once_cell::sync::Lazy<T> {
fn is_match(&self, haystack: &str) -> bool {
once_cell::sync::Lazy::force(self).is_match(haystack)
}
}
impl AsStr for Regex {
fn as_str(&self) -> &str {
self.as_str()
}
}
impl<T: AsStr> AsStr for once_cell::sync::Lazy<T> {
fn as_str(&self) -> &str {
once_cell::sync::Lazy::force(self).as_str()
}
}
pub type StaticPattern = once_cell::sync::Lazy<Regex>;
#[macro_export]
macro_rules! __init_pattern {
($pat:literal) => {
$crate::rules::pattern::regex::StaticPattern::new(|| {
$crate::rules::pattern::regex::Regex::new($pat).unwrap()
})
};
}
pub use crate::__init_pattern as init_pattern;
}