use crate::pattern::{Pattern, PatternError};
use crate::substitution::SubstitutionTable;
use std::collections::BTreeMap;
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PatternSyntaxError {
message: String,
}
impl PatternSyntaxError {
#[must_use]
pub fn message(&self) -> &str {
&self.message
}
}
impl fmt::Display for PatternSyntaxError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.message)
}
}
impl std::error::Error for PatternSyntaxError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WildcardPattern {
inner: Pattern,
}
impl WildcardPattern {
pub fn compile(source: &str, case_sensitive: bool) -> Result<Self, PatternSyntaxError> {
Self::compile_with(source, case_sensitive, &BTreeMap::new())
}
pub fn compile_with(
source: &str,
case_sensitive: bool,
variables: &BTreeMap<String, Vec<String>>,
) -> Result<Self, PatternSyntaxError> {
let table = SubstitutionTable::from_custom(variables.clone());
let mut errors = Vec::new();
let inner = Pattern::compile(source, case_sensitive, &table, &mut errors);
if let Some(error) = errors.first() {
return Err(PatternSyntaxError {
message: match error {
PatternError::UnterminatedReference => {
format!("`{source}` contains a `$(` that is never closed")
}
PatternError::UnknownVariable(name) => format!(
"`$({name})` is neither predefined nor supplied as a custom variable"
),
PatternError::NestedSubstitution { variable, value } => format!(
"substitution value `{value}` references `$({variable})`, which Apple does \
not allow"
),
PatternError::EmptyVariable(name) => {
format!("`$({name})` has no values, so the pattern can never match")
}
},
});
}
Ok(Self { inner })
}
#[must_use]
pub fn matches(&self, input: &str) -> bool {
self.inner.matches(input)
}
#[must_use]
pub fn matches_with_case(&self, input: &str, case_sensitive: bool) -> bool {
self.inner.matches_with(input, case_sensitive)
}
#[must_use]
pub fn source(&self) -> &str {
self.inner.source()
}
}