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}