dcbor_pattern/pattern/meta/
search_pattern.rs1use dcbor::prelude::*;
2
3use crate::pattern::{Matcher, Path, Pattern, vm::Instr};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct SearchPattern(Box<Pattern>);
11
12impl SearchPattern {
13 pub fn new(pattern: Pattern) -> Self { SearchPattern(Box::new(pattern)) }
15
16 pub fn pattern(&self) -> &Pattern { &self.0 }
18
19 fn search_recursive(
21 &self,
22 cbor: &CBOR,
23 path: Vec<CBOR>,
24 results: &mut Vec<Path>,
25 ) {
26 let pattern_paths = self.0.paths(cbor);
28
29 if !pattern_paths.is_empty() {
31 results.push(path.clone());
32 }
33
34 match cbor.as_case() {
36 CBORCase::Array(arr) => {
37 for child in arr.iter() {
38 let mut new_path = path.clone();
39 new_path.push(child.clone());
40 self.search_recursive(child, new_path, results);
41 }
42 }
43 CBORCase::Map(map) => {
44 for (key, value) in map.iter() {
45 let mut key_path = path.clone();
47 key_path.push(key.clone());
48 self.search_recursive(key, key_path, results);
49
50 let mut value_path = path.clone();
51 value_path.push(value.clone());
52 self.search_recursive(value, value_path, results);
53 }
54 }
55 CBORCase::Tagged(_, content) => {
56 let mut new_path = path.clone();
57 new_path.push(content.clone());
58 self.search_recursive(content, new_path, results);
59 }
60 _ => {
61 }
63 }
64 }
65
66 fn search_recursive_with_captures(
69 &self,
70 cbor: &CBOR,
71 path: Vec<CBOR>,
72 results: &mut Vec<Path>,
73 all_captures: &mut std::collections::HashMap<String, Vec<Path>>,
74 ) {
75 let (pattern_paths, captures) = self.0.paths_with_captures(cbor);
77
78 if !pattern_paths.is_empty() {
81 results.push(path.clone());
82
83 for (name, _capture_paths) in captures {
87 all_captures.entry(name).or_default().push(path.clone());
90 }
91 }
92
93 match cbor.as_case() {
95 CBORCase::Array(arr) => {
96 for child in arr.iter() {
97 let mut new_path = path.clone();
98 new_path.push(child.clone());
99 self.search_recursive_with_captures(
100 child,
101 new_path,
102 results,
103 all_captures,
104 );
105 }
106 }
107 CBORCase::Map(map) => {
108 for (key, value) in map.iter() {
109 let mut key_path = path.clone();
111 key_path.push(key.clone());
112 self.search_recursive_with_captures(
113 key,
114 key_path,
115 results,
116 all_captures,
117 );
118
119 let mut value_path = path.clone();
120 value_path.push(value.clone());
121 self.search_recursive_with_captures(
122 value,
123 value_path,
124 results,
125 all_captures,
126 );
127 }
128 }
129 CBORCase::Tagged(_, content) => {
130 let mut tagged_path = path.clone();
131 tagged_path.push(content.clone());
132 self.search_recursive_with_captures(
133 content,
134 tagged_path,
135 results,
136 all_captures,
137 );
138 }
139 _ => {
140 }
142 }
143 }
144}
145
146impl Default for SearchPattern {
147 fn default() -> Self {
148 Self::new(Pattern::any())
150 }
151}
152
153impl Matcher for SearchPattern {
154 fn paths(&self, haystack: &CBOR) -> Vec<Path> {
155 let mut result_paths = Vec::new();
156 self.search_recursive(haystack, vec![haystack.clone()], &mut result_paths);
157
158 let mut seen = std::collections::HashSet::new();
160 let mut unique = Vec::new();
161 for path in result_paths {
162 let path_key: Vec<_> = path
164 .iter()
165 .map(|cbor| cbor.to_cbor_data()) .collect();
167 if seen.insert(path_key) {
168 unique.push(path);
169 }
170 }
171
172 unique
173 }
174
175 fn paths_with_captures(
176 &self,
177 haystack: &CBOR,
178 ) -> (Vec<Path>, std::collections::HashMap<String, Vec<Path>>) {
179 let mut result_paths = Vec::new();
180 let mut all_captures = std::collections::HashMap::new();
181
182 self.search_recursive_with_captures(
183 haystack,
184 vec![haystack.clone()],
185 &mut result_paths,
186 &mut all_captures,
187 );
188
189 let mut seen = std::collections::HashSet::new();
191 let mut unique_paths = Vec::new();
192 for path in result_paths {
193 let path_key: Vec<_> =
194 path.iter().map(|cbor| cbor.to_cbor_data()).collect();
195 if seen.insert(path_key) {
196 unique_paths.push(path);
197 }
198 }
199
200 (unique_paths, all_captures)
201 }
202
203 fn collect_capture_names(&self, names: &mut Vec<String>) {
204 self.0.collect_capture_names(names);
206 }
207
208 fn compile(
209 &self,
210 code: &mut Vec<Instr>,
211 literals: &mut Vec<Pattern>,
212 captures: &mut Vec<String>,
213 ) {
214 let idx = literals.len();
215 literals.push((*self.0).clone());
216
217 let mut inner_names = Vec::new();
219 self.0.collect_capture_names(&mut inner_names);
220 let mut capture_map = Vec::new();
221
222 for name in inner_names {
223 let pos = if let Some(i) = captures.iter().position(|n| n == &name)
224 {
225 i
226 } else {
227 let i = captures.len();
228 captures.push(name.clone());
229 i
230 };
231 capture_map.push((name, pos));
232 }
233
234 code.push(Instr::Search { pat_idx: idx, capture_map });
235 }
236}
237
238impl std::fmt::Display for SearchPattern {
239 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240 write!(f, "search({})", self.pattern())
241 }
242}