tytanic_filter/ast/
pat.rs1use std::hash::Hash;
2
3use pest::iterators::Pair;
4
5use super::{Error, Glob, PairExt, PairsExt, Regex, Rule, Str};
6use crate::eval::{self, Context, Eval, Set, Test, Value};
7
8#[derive(Clone, PartialEq, Eq, Hash)]
10pub enum Pat {
11 Glob(Glob),
13
14 Regex(Regex),
16
17 Exact(Str),
19}
20
21impl std::fmt::Debug for Pat {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 let (prefix, pat) = match self {
24 Pat::Glob(glob) => ("glob", glob.as_str()),
25 Pat::Regex(regex) => ("regex", regex.as_str()),
26 Pat::Exact(pat) => ("exact", pat.as_str()),
27 };
28
29 write!(f, "{prefix}:{pat:?}")
30 }
31}
32
33impl Pat {
34 pub fn is_match<S: AsRef<str>>(&self, id: S) -> bool {
36 match self {
37 Self::Glob(pat) => pat.is_match(id),
38 Self::Regex(regex) => regex.is_match(id),
39 Self::Exact(pat) => id.as_ref() == pat.as_str(),
40 }
41 }
42}
43
44impl<T: Test> Eval<T> for Pat {
45 fn eval(&self, _ctx: &Context<T>) -> Result<Value<T>, eval::Error> {
46 Ok(Value::Set(Set::coerce_pat(self.clone())))
47 }
48}
49
50impl Pat {
51 pub(super) fn parse(pair: Pair<'_, Rule>) -> Result<Self, Error> {
52 pair.expect_rules(&[Rule::pat_inner])?;
53 let mut pairs = pair.into_inner();
54
55 let kind = pairs.expect_pair(&[Rule::pat_kind])?.as_str();
56 let _ = pairs.expect_pair(&[Rule::pat_sep])?;
57 let inner = pairs.expect_pair(&[Rule::pat_raw_lit, Rule::str_double, Rule::str_single])?;
58 pairs.expect_end()?;
59
60 let pat: Str = if inner.as_rule() == Rule::pat_raw_lit {
61 Str(inner.as_str().into())
62 } else {
63 Str::parse(inner)?
64 };
65
66 Ok(match kind {
67 "g" | "glob" => Self::Glob(Glob::new(&pat)?),
68 "r" | "regex" => Self::Regex(Regex::new(&pat)?),
69 "e" | "exact" => Self::Exact(pat),
70 _ => unreachable!("unhandled kind: {kind:?}"),
71 })
72 }
73}