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 {
91 if capture_paths.len() > 1
92 || (capture_paths.len() == 1
93 && capture_paths[0].len() > path.len())
94 {
95 for capture_path in capture_paths {
99 let mut transformed_path = path.clone();
102 if capture_path.len() > 1 {
105 transformed_path
106 .extend_from_slice(&capture_path[1..]);
107 }
108 all_captures
109 .entry(name.clone())
110 .or_default()
111 .push(transformed_path);
112 }
113 } else {
114 all_captures.entry(name).or_default().push(path.clone());
117 }
118 }
119 }
120
121 match cbor.as_case() {
123 CBORCase::Array(arr) => {
124 for child in arr.iter() {
125 let mut new_path = path.clone();
126 new_path.push(child.clone());
127 self.search_recursive_with_captures(
128 child,
129 new_path,
130 results,
131 all_captures,
132 );
133 }
134 }
135 CBORCase::Map(map) => {
136 for (key, value) in map.iter() {
137 let mut key_path = path.clone();
139 key_path.push(key.clone());
140 self.search_recursive_with_captures(
141 key,
142 key_path,
143 results,
144 all_captures,
145 );
146
147 let mut value_path = path.clone();
148 value_path.push(value.clone());
149 self.search_recursive_with_captures(
150 value,
151 value_path,
152 results,
153 all_captures,
154 );
155 }
156 }
157 CBORCase::Tagged(_, content) => {
158 let mut tagged_path = path.clone();
159 tagged_path.push(content.clone());
160 self.search_recursive_with_captures(
161 content,
162 tagged_path,
163 results,
164 all_captures,
165 );
166 }
167 _ => {
168 }
170 }
171 }
172}
173
174impl Default for SearchPattern {
175 fn default() -> Self {
176 Self::new(Pattern::any())
178 }
179}
180
181impl Matcher for SearchPattern {
182 fn paths(&self, haystack: &CBOR) -> Vec<Path> {
183 let mut result_paths = Vec::new();
184 self.search_recursive(
185 haystack,
186 vec![haystack.clone()],
187 &mut result_paths,
188 );
189
190 let mut seen = std::collections::HashSet::new();
192 let mut unique = Vec::new();
193 for path in result_paths {
194 let path_key: Vec<_> = path
196 .iter()
197 .map(|cbor| cbor.to_cbor_data()) .collect();
199 if seen.insert(path_key) {
200 unique.push(path);
201 }
202 }
203
204 unique
205 }
206
207 fn paths_with_captures(
208 &self,
209 haystack: &CBOR,
210 ) -> (Vec<Path>, std::collections::HashMap<String, Vec<Path>>) {
211 let mut result_paths = Vec::new();
212 let mut all_captures = std::collections::HashMap::new();
213
214 self.search_recursive_with_captures(
215 haystack,
216 vec![haystack.clone()],
217 &mut result_paths,
218 &mut all_captures,
219 );
220
221 let mut seen = std::collections::HashSet::new();
223 let mut unique_paths = Vec::new();
224 for path in result_paths {
225 let path_key: Vec<_> =
226 path.iter().map(|cbor| cbor.to_cbor_data()).collect();
227 if seen.insert(path_key) {
228 unique_paths.push(path);
229 }
230 }
231
232 (unique_paths, all_captures)
233 }
234
235 fn collect_capture_names(&self, names: &mut Vec<String>) {
236 self.0.collect_capture_names(names);
238 }
239
240 fn compile(
241 &self,
242 code: &mut Vec<Instr>,
243 literals: &mut Vec<Pattern>,
244 captures: &mut Vec<String>,
245 ) {
246 let idx = literals.len();
247 literals.push((*self.0).clone());
248
249 let mut inner_names = Vec::new();
251 self.0.collect_capture_names(&mut inner_names);
252 let mut capture_map = Vec::new();
253
254 for name in inner_names {
255 let pos = if let Some(i) = captures.iter().position(|n| n == &name)
256 {
257 i
258 } else {
259 let i = captures.len();
260 captures.push(name.clone());
261 i
262 };
263 capture_map.push((name, pos));
264 }
265
266 code.push(Instr::Search { pat_idx: idx, capture_map });
267 }
268}
269
270impl std::fmt::Display for SearchPattern {
271 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
272 write!(f, "search({})", self.pattern())
273 }
274}