use std::collections::HashMap;
use bc_envelope::prelude::*;
use crate::pattern::{Matcher, Path, Pattern, vm::Instr};
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum SubjectPattern {
Any,
Pattern(Box<Pattern>),
}
impl SubjectPattern {
pub fn any() -> Self { SubjectPattern::Any }
pub fn pattern(pattern: Pattern) -> Self {
SubjectPattern::Pattern(Box::new(pattern))
}
}
impl Matcher for SubjectPattern {
fn paths_with_captures(
&self,
haystack: &Envelope,
) -> (Vec<Path>, HashMap<String, Vec<Path>>) {
let paths = {
let subject = haystack.subject();
match self {
SubjectPattern::Any => {
vec![vec![subject.clone()]]
}
SubjectPattern::Pattern(pattern) => {
if pattern.matches(&subject) {
vec![vec![subject.clone()]]
} else {
vec![]
}
}
}
};
(paths, HashMap::new())
}
fn compile(
&self,
code: &mut Vec<Instr>,
literals: &mut Vec<Pattern>,
captures: &mut Vec<String>,
) {
match self {
SubjectPattern::Any => {
code.push(Instr::NavigateSubject);
}
SubjectPattern::Pattern(pattern) => {
code.push(Instr::NavigateSubject);
code.push(Instr::ExtendTraversal);
pattern.compile(code, literals, captures);
code.push(Instr::CombineTraversal);
}
}
}
}
impl std::fmt::Display for SubjectPattern {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SubjectPattern::Any => write!(f, "subj"),
SubjectPattern::Pattern(pattern) => {
write!(f, "subj({})", pattern)
}
}
}
}