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 (
39 vec![vec![haystack.clone()]],
40 std::collections::HashMap::new(),
41 )
42 } else {
43 (vec![], std::collections::HashMap::new())
45 }
46 }
47
48 fn compile(
50 &self,
51 code: &mut Vec<Instr>,
52 literals: &mut Vec<Pattern>,
53 _captures: &mut Vec<String>,
54 ) {
55 let idx = literals.len();
57 literals.push(self.pattern().clone());
58 code.push(Instr::NotMatch { pat_idx: idx });
59 }
60
61 fn collect_capture_names(&self, names: &mut Vec<String>) {
62 let _ = names; }
68
69 fn is_complex(&self) -> bool {
70 true
72 }
73}
74
75impl std::fmt::Display for NotPattern {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 if self.pattern().is_complex() {
78 write!(f, "!({})", self.pattern())
79 } else {
80 write!(f, "!{}", self.pattern())
81 }
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn test_not_pattern_display() {
91 let not_pattern = NotPattern::new(Pattern::number(5));
92 assert_eq!(not_pattern.to_string(), "!5");
93 }
94
95 #[test]
96 fn test_not_pattern_display_complex() {
97 let and_pattern =
98 Pattern::Meta(crate::pattern::meta::MetaPattern::And(
99 crate::pattern::meta::AndPattern::new(vec![
100 Pattern::number(5),
101 Pattern::text("hello"),
102 ]),
103 ));
104 let not_pattern = NotPattern::new(and_pattern);
105 assert_eq!(not_pattern.to_string(), r#"!(5 & "hello")"#);
106 }
107
108 #[test]
109 fn test_not_pattern_matches_when_inner_fails() {
110 let pattern = NotPattern::new(Pattern::number(5));
111
112 let cbor_42 = CBOR::from(42); assert!(pattern.matches(&cbor_42));
114
115 let cbor_text = CBOR::from("hello"); assert!(pattern.matches(&cbor_text));
117 }
118
119 #[test]
120 fn test_not_pattern_fails_when_inner_matches() {
121 let pattern = NotPattern::new(Pattern::number(5));
122
123 let cbor_5 = CBOR::from(5); assert!(!pattern.matches(&cbor_5));
125 }
126}