dcbor_pattern/pattern/meta/
not_pattern.rs1use dcbor::prelude::*;
2
3use crate::pattern::{Matcher, Path, Pattern, vm::Instr};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct NotPattern(Box<Pattern>);
9
10impl NotPattern {
11    pub fn new(pattern: Pattern) -> Self { NotPattern(Box::new(pattern)) }
13
14    pub fn pattern(&self) -> &Pattern { &self.0 }
16}
17
18impl Matcher for NotPattern {
19    fn paths(&self, haystack: &CBOR) -> Vec<Path> {
20        if !self.pattern().matches(haystack) {
23            vec![vec![haystack.clone()]]
24        } else {
25            vec![]
26        }
27    }
28
29    fn paths_with_captures(
30        &self,
31        haystack: &CBOR,
32    ) -> (Vec<Path>, std::collections::HashMap<String, Vec<Path>>) {
33        let (inner_paths, _inner_captures) =
35            self.pattern().paths_with_captures(haystack);
36        if inner_paths.is_empty() {
37            (vec![vec![haystack.clone()]], std::collections::HashMap::new())
39        } else {
40            (vec![], std::collections::HashMap::new())
42        }
43    }
44
45    fn compile(
47        &self,
48        code: &mut Vec<Instr>,
49        literals: &mut Vec<Pattern>,
50        _captures: &mut Vec<String>,
51    ) {
52        let idx = literals.len();
54        literals.push(self.pattern().clone());
55        code.push(Instr::NotMatch { pat_idx: idx });
56    }
57
58    fn collect_capture_names(&self, names: &mut Vec<String>) {
59        let _ = names; }
65
66    fn is_complex(&self) -> bool {
67        true
69    }
70}
71
72impl std::fmt::Display for NotPattern {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        if self.pattern().is_complex() {
75            write!(f, "!({})", self.pattern())
76        } else {
77            write!(f, "!{}", self.pattern())
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn test_not_pattern_display() {
88        let not_pattern = NotPattern::new(Pattern::number(5));
89        assert_eq!(not_pattern.to_string(), "!5");
90    }
91
92    #[test]
93    fn test_not_pattern_display_complex() {
94        let and_pattern =
95            Pattern::Meta(crate::pattern::meta::MetaPattern::And(
96                crate::pattern::meta::AndPattern::new(vec![
97                    Pattern::number(5),
98                    Pattern::text("hello"),
99                ]),
100            ));
101        let not_pattern = NotPattern::new(and_pattern);
102        assert_eq!(not_pattern.to_string(), r#"!(5 & "hello")"#);
103    }
104
105    #[test]
106    fn test_not_pattern_matches_when_inner_fails() {
107        let pattern = NotPattern::new(Pattern::number(5));
108
109        let cbor_42 = CBOR::from(42); assert!(pattern.matches(&cbor_42));
111
112        let cbor_text = CBOR::from("hello"); assert!(pattern.matches(&cbor_text));
114    }
115
116    #[test]
117    fn test_not_pattern_fails_when_inner_matches() {
118        let pattern = NotPattern::new(Pattern::number(5));
119
120        let cbor_5 = CBOR::from(5); assert!(!pattern.matches(&cbor_5));
122    }
123}