use dcbor::prelude::*;
use crate::pattern::{Matcher, Path, Pattern, vm::Instr};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AndPattern(Vec<Pattern>);
impl AndPattern {
pub fn new(patterns: Vec<Pattern>) -> Self { AndPattern(patterns) }
pub fn patterns(&self) -> &[Pattern] { &self.0 }
}
impl Matcher for AndPattern {
fn paths(&self, haystack: &CBOR) -> Vec<Path> {
if self
.patterns()
.iter()
.all(|pattern| pattern.matches(haystack))
{
vec![vec![haystack.clone()]]
} else {
vec![]
}
}
fn paths_with_captures(
&self,
haystack: &CBOR,
) -> (Vec<Path>, std::collections::HashMap<String, Vec<Path>>) {
let mut all_captures = std::collections::HashMap::new();
for pattern in self.patterns() {
let (paths, captures) = pattern.paths_with_captures(haystack);
if paths.is_empty() {
return (vec![], std::collections::HashMap::new());
}
for (name, capture_paths) in captures {
all_captures
.entry(name)
.or_insert_with(Vec::new)
.extend(capture_paths);
}
}
(vec![vec![haystack.clone()]], all_captures)
}
fn compile(
&self,
code: &mut Vec<Instr>,
lits: &mut Vec<Pattern>,
captures: &mut Vec<String>,
) {
for pattern in self.patterns() {
pattern.compile(code, lits, captures);
}
}
fn collect_capture_names(&self, names: &mut Vec<String>) {
for pattern in self.patterns() {
pattern.collect_capture_names(names);
}
}
fn is_complex(&self) -> bool {
self.patterns().len() > 1
|| self.patterns().iter().any(|p| p.is_complex())
}
}
impl std::fmt::Display for AndPattern {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.patterns()
.iter()
.map(|p| p.to_string())
.collect::<Vec<_>>()
.join(" & ")
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_and_pattern_display() {
let pattern1 = Pattern::number_greater_than(5);
let pattern2 = Pattern::number_less_than(10);
let and_pattern = AndPattern::new(vec![pattern1, pattern2]);
assert_eq!(and_pattern.to_string(), ">5 & <10");
}
#[test]
fn test_and_pattern_matches_when_all_patterns_match() {
let pattern = AndPattern::new(vec![
Pattern::number_greater_than(5),
Pattern::number_less_than(10),
]);
let cbor_7 = CBOR::from(7);
assert!(pattern.matches(&cbor_7));
}
#[test]
fn test_and_pattern_fails_when_any_pattern_fails() {
let pattern = AndPattern::new(vec![
Pattern::number_greater_than(5),
Pattern::number_less_than(10),
]);
let cbor_12 = CBOR::from(12); assert!(!pattern.matches(&cbor_12));
let cbor_3 = CBOR::from(3); assert!(!pattern.matches(&cbor_3));
}
#[test]
fn test_and_pattern_empty_returns_true() {
let pattern = AndPattern::new(vec![]);
let cbor = CBOR::from("any value");
assert!(pattern.matches(&cbor));
}
}