dcbor_pattern/pattern/meta/
repeat_pattern.rs1use dcbor::prelude::*;
2
3use crate::{
4 Quantifier,
5 pattern::{Matcher, Path, Pattern, vm::Instr},
6};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct RepeatPattern {
11 pattern: Box<Pattern>,
12 quantifier: Quantifier,
13}
14
15impl RepeatPattern {
16 pub fn repeat(pattern: Pattern, quantifier: Quantifier) -> Self {
19 RepeatPattern { pattern: Box::new(pattern), quantifier }
20 }
21
22 pub fn new(pattern: Pattern) -> Self {
25 RepeatPattern {
26 pattern: Box::new(pattern),
27 quantifier: Quantifier::default(),
28 }
29 }
30
31 pub fn pattern(&self) -> &Pattern { &self.pattern }
33
34 pub fn quantifier(&self) -> &Quantifier { &self.quantifier }
36}
37
38impl Matcher for RepeatPattern {
39 fn paths(&self, haystack: &CBOR) -> Vec<Path> {
40 let inner_paths = self.pattern.paths(haystack);
45 let matches = !inner_paths.is_empty();
46
47 if matches {
48 if self.quantifier.contains(1) {
50 inner_paths
51 } else {
52 vec![]
53 }
54 } else {
55 if self.quantifier.contains(0) {
57 vec![vec![haystack.clone()]]
59 } else {
60 vec![]
62 }
63 }
64 }
65
66 fn paths_with_captures(
67 &self,
68 haystack: &CBOR,
69 ) -> (Vec<Path>, std::collections::HashMap<String, Vec<Path>>) {
70 let mut capture_names = Vec::new();
72 self.pattern.collect_capture_names(&mut capture_names);
73
74 if capture_names.is_empty() {
75 return (self.paths(haystack), std::collections::HashMap::new());
77 }
78
79 match haystack.as_case() {
82 CBORCase::Array(arr) => {
83 let mut all_captures = std::collections::HashMap::new();
86 let mut valid_match = false;
87
88 if self.quantifier.contains(arr.len()) {
90 valid_match = true;
91
92 if arr.is_empty() && self.quantifier.contains(0) {
95 for name in &capture_names {
98 all_captures.insert(name.clone(), vec![]);
99 }
100 } else {
101 for element in arr {
104 let (_element_paths, element_captures) =
105 self.pattern.paths_with_captures(element);
106
107 for (capture_name, captured_paths) in
108 element_captures
109 {
110 all_captures
111 .entry(capture_name)
112 .or_insert_with(Vec::new)
113 .extend(captured_paths);
114 }
115 }
116 }
117 }
118
119 if valid_match {
120 (vec![vec![haystack.clone()]], all_captures)
121 } else {
122 (vec![], std::collections::HashMap::new())
123 }
124 }
125 _ => {
126 let inner_paths = self.pattern.paths(haystack);
128 let matches = !inner_paths.is_empty();
129
130 if matches && self.quantifier.contains(1) {
131 let (_paths, captures) =
133 self.pattern.paths_with_captures(haystack);
134 (vec![vec![haystack.clone()]], captures)
135 } else if !matches && self.quantifier.contains(0) {
136 let mut empty_captures = std::collections::HashMap::new();
139 for name in &capture_names {
140 empty_captures.insert(name.clone(), vec![]);
141 }
142 (vec![vec![haystack.clone()]], empty_captures)
143 } else {
144 (vec![], std::collections::HashMap::new())
146 }
147 }
148 }
149 }
150
151 fn compile(
152 &self,
153 code: &mut Vec<Instr>,
154 literals: &mut Vec<Pattern>,
155 _captures: &mut Vec<String>,
156 ) {
157 let idx = literals.len();
159 literals.push((*self.pattern).clone());
160 code.push(Instr::Repeat { pat_idx: idx, quantifier: self.quantifier });
161 }
162
163 fn collect_capture_names(&self, names: &mut Vec<String>) {
164 self.pattern.collect_capture_names(names);
166 }
167}
168
169impl std::fmt::Display for RepeatPattern {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 let formatted_range = self.quantifier.to_string();
172 write!(f, "({}){}", self.pattern, formatted_range)
173 }
174}