1use super::Matcher;
4use crate::{
5 error,
6 path::{Element, Path},
7 streamer::ParsedKind,
8};
9use std::str::FromStr;
10
11type StringMatch = Option<String>;
13
14#[derive(Debug, Clone, PartialEq)]
16struct IndexMatch(Vec<(Option<usize>, Option<usize>)>);
17
18impl FromStr for IndexMatch {
19 type Err = error::Matcher;
20
21 fn from_str(path: &str) -> Result<Self, Self::Err> {
22 let splitted = path.split(',');
23 let mut result = vec![];
24
25 for item_str in splitted {
26 let inner_splitted: Vec<_> = item_str.split('-').collect();
27 match inner_splitted.len() {
28 1 => {
29 let index: usize = inner_splitted[0]
30 .parse()
31 .map_err(|_| error::Matcher::Parse(inner_splitted[0].to_string()))?;
32 result.push((Some(index), Some(index + 1)));
33 }
34 2 => {
35 let start_opt: Option<usize> =
36 if inner_splitted[0].is_empty() {
37 None
38 } else {
39 Some(inner_splitted[0].parse().map_err(|_| {
40 error::Matcher::Parse(inner_splitted[0].to_string())
41 })?)
42 };
43 let end_opt: Option<usize> =
44 if inner_splitted[1].is_empty() {
45 None
46 } else {
47 Some(inner_splitted[1].parse().map_err(|_| {
48 error::Matcher::Parse(inner_splitted[1].to_string())
49 })?)
50 };
51 match (start_opt, end_opt) {
52 (Some(start), Some(end)) => {
53 if start >= end {
54 return Err(error::Matcher::Parse(item_str.to_string()));
55 }
56 }
57 (None, None) => return Err(error::Matcher::Parse(item_str.to_string())),
58 _ => {}
59 }
60 result.push((start_opt, end_opt));
61 }
62 _ => return Err(error::Matcher::Parse(item_str.to_string())),
63 }
64 }
65
66 Ok(Self(result))
67 }
68}
69
70#[derive(Debug, Clone, PartialEq)]
72enum SimplePathElement {
73 Key(StringMatch),
74 Index(IndexMatch),
75 WildCardSingle,
76 WildCardAny,
77}
78
79impl PartialEq<Element> for SimplePathElement {
80 fn eq(&self, other: &Element) -> bool {
81 match &self {
82 SimplePathElement::Key(None) => other.is_key(),
83 SimplePathElement::Key(Some(key)) => {
84 if let Element::Key(pkey) = other {
85 key == pkey
86 } else {
87 false
88 }
89 }
90 SimplePathElement::Index(idx_matches) => {
91 if let Element::Index(idx) = other {
92 if idx_matches.0.is_empty() {
93 true
94 } else {
95 idx_matches.0.iter().any(|(min_opt, max_opt)| {
96 if let Some(max) = max_opt {
97 if idx >= max {
98 return false;
99 }
100 }
101 if let Some(min) = min_opt {
102 if idx < min {
103 return false;
104 }
105 }
106 true
107 })
108 }
109 } else {
110 false
111 }
112 }
113 SimplePathElement::WildCardAny => true,
114 SimplePathElement::WildCardSingle => true,
115 }
116 }
117}
118
119#[derive(Default, Debug, Clone)]
125pub struct Simple {
126 path: Vec<SimplePathElement>,
127}
128
129#[derive(Debug, PartialEq)]
130enum SimpleMatcherStates {
131 ElementStart,
132 Array,
133 ObjectStart,
134 Object(bool),
135 ObjectEnd,
136}
137
138impl Matcher for Simple {
139 fn match_path(&self, path: &Path, _kind: ParsedKind) -> bool {
140 if !self
143 .path
144 .iter()
145 .any(|e| matches!(e, SimplePathElement::WildCardAny))
146 && path.depth() != self.path.len()
147 {
148 return false;
149 }
150
151 let path = path.get_path();
152
153 let mut indexes = vec![(0, 0)];
156
157 while !indexes.is_empty() {
158 let (spath_idx, path_idx) = indexes.pop().unwrap();
159
160 if spath_idx == self.path.len() && path_idx == path.len() {
161 return true;
163 }
164
165 if spath_idx >= self.path.len() {
166 continue;
168 }
169
170 match self.path[spath_idx] {
172 SimplePathElement::WildCardAny => {
173 indexes.push((spath_idx + 1, path_idx)); if path_idx < path.len() {
175 indexes.push((spath_idx, path_idx + 1)); }
177 }
178 _ => {
179 if path_idx >= path.len() {
180 continue;
181 } else if self.path[spath_idx] == path[path_idx] {
182 indexes.push((spath_idx + 1, path_idx + 1));
183 } else {
184 continue;
185 }
186 }
187 }
188 }
189
190 false
191 }
192}
193
194impl FromStr for Simple {
195 type Err = error::Matcher;
196
197 fn from_str(path: &str) -> Result<Self, Self::Err> {
198 let mut state = SimpleMatcherStates::ElementStart;
199 let mut buffer = vec![];
200 let mut result = vec![];
201
202 for chr in path.chars() {
203 state = match state {
204 SimpleMatcherStates::ElementStart => match chr {
205 '[' => SimpleMatcherStates::Array,
206 '{' => SimpleMatcherStates::ObjectStart,
207 '?' => {
208 result.push(SimplePathElement::WildCardSingle);
209 SimpleMatcherStates::ElementStart
210 }
211 '*' => {
212 result.push(SimplePathElement::WildCardAny);
213 SimpleMatcherStates::ElementStart
214 }
215 _ => {
216 return Err(error::Matcher::Parse(path.to_string()));
217 }
218 },
219 SimpleMatcherStates::Array => match chr {
220 ']' => {
221 let new_element = if buffer.is_empty() {
222 SimplePathElement::Index(IndexMatch(vec![]))
223 } else {
224 SimplePathElement::Index(
225 buffer
226 .drain(..)
227 .collect::<String>()
228 .parse()
229 .map_err(|_| error::Matcher::Parse(path.to_string()))?,
230 )
231 };
232 result.push(new_element);
233 SimpleMatcherStates::ElementStart
234 }
235 '0'..='9' | '-' | ',' => {
236 buffer.push(chr);
237 SimpleMatcherStates::Array
238 }
239 _ => {
240 return Err(error::Matcher::Parse(path.to_string()));
241 }
242 },
243 SimpleMatcherStates::ObjectStart => match chr {
244 '}' => {
245 result.push(SimplePathElement::Key(None));
246 SimpleMatcherStates::ElementStart
247 }
248 '"' => SimpleMatcherStates::Object(false),
249 _ => {
250 return Err(error::Matcher::Parse(path.to_string()));
251 }
252 },
253 SimpleMatcherStates::Object(false) => match chr {
254 '"' => SimpleMatcherStates::ObjectEnd,
255 '\\' => {
256 buffer.push(chr);
257 SimpleMatcherStates::Object(true)
258 }
259 _ => {
260 buffer.push(chr);
261 SimpleMatcherStates::Object(false)
262 }
263 },
264 SimpleMatcherStates::Object(true) => {
265 buffer.push(chr);
266 SimpleMatcherStates::Object(false)
267 }
268 SimpleMatcherStates::ObjectEnd => match chr {
269 '}' => {
270 result.push(SimplePathElement::Key(Some(buffer.drain(..).collect())));
271 SimpleMatcherStates::ElementStart
272 }
273 _ => {
274 return Err(error::Matcher::Parse(path.to_string()));
275 }
276 },
277 }
278 }
279 if state == SimpleMatcherStates::ElementStart {
280 Ok(Self { path: result })
281 } else {
282 Err(error::Matcher::Parse(path.to_string()))
283 }
284 }
285}
286
287impl Simple {
288 pub fn new(path_expr: &str) -> Result<Self, error::Matcher> {
293 Self::from_str(path_expr)
294 }
295}
296
297#[cfg(test)]
298mod tests {
299 use super::{Matcher, Simple};
300 use crate::{path::Path, streamer::ParsedKind};
301 use std::{convert::TryFrom, str::FromStr};
302
303 #[test]
304 fn exact() {
305 let simple = Simple::from_str(r#"{"People"}[0]{"Height"}"#).unwrap();
306
307 assert!(!simple.match_path(&Path::try_from(r#"{"People"}"#).unwrap(), ParsedKind::Arr));
308 assert!(!simple.match_path(
309 &Path::try_from(r#"{"People"}[0]"#).unwrap(),
310 ParsedKind::Obj
311 ));
312 assert!(!simple.match_path(
313 &Path::try_from(r#"{"People"}[0]{"Age"}"#).unwrap(),
314 ParsedKind::Num
315 ));
316 assert!(simple.match_path(
317 &Path::try_from(r#"{"People"}[0]{"Height"}"#).unwrap(),
318 ParsedKind::Num
319 ));
320 assert!(!simple.match_path(
321 &Path::try_from(r#"{"People"}[1]"#).unwrap(),
322 ParsedKind::Obj
323 ));
324 assert!(!simple.match_path(
325 &Path::try_from(r#"{"People"}[1]{"Age"}"#).unwrap(),
326 ParsedKind::Num
327 ));
328 assert!(!simple.match_path(
329 &Path::try_from(r#"{"People"}[1]{"Height"}"#).unwrap(),
330 ParsedKind::Num
331 ));
332 }
333
334 #[test]
335 fn wild_array() {
336 let simple = Simple::from_str(r#"{"People"}[]{"Height"}"#).unwrap();
337
338 assert!(!simple.match_path(&Path::try_from(r#"{"People"}"#).unwrap(), ParsedKind::Arr));
339 assert!(!simple.match_path(
340 &Path::try_from(r#"{"People"}[0]"#).unwrap(),
341 ParsedKind::Obj
342 ));
343 assert!(!simple.match_path(
344 &Path::try_from(r#"{"People"}[0]{"Age"}"#).unwrap(),
345 ParsedKind::Num
346 ));
347 assert!(simple.match_path(
348 &Path::try_from(r#"{"People"}[0]{"Height"}"#).unwrap(),
349 ParsedKind::Num
350 ));
351 assert!(!simple.match_path(
352 &Path::try_from(r#"{"People"}[1]"#).unwrap(),
353 ParsedKind::Obj
354 ));
355 assert!(!simple.match_path(
356 &Path::try_from(r#"{"People"}[1]{"Age"}"#).unwrap(),
357 ParsedKind::Num
358 ));
359 assert!(simple.match_path(
360 &Path::try_from(r#"{"People"}[1]{"Height"}"#).unwrap(),
361 ParsedKind::Num
362 ));
363 }
364
365 #[test]
366 fn ranges_array() {
367 let simple = Simple::from_str(r#"{"People"}[3,4-5,5,-3,6-]{"Height"}"#).unwrap();
368
369 assert!(simple.match_path(
370 &Path::try_from(r#"{"People"}[0]{"Height"}"#).unwrap(),
371 ParsedKind::Num
372 ));
373 assert!(simple.match_path(
374 &Path::try_from(r#"{"People"}[1]{"Height"}"#).unwrap(),
375 ParsedKind::Num
376 ));
377 assert!(simple.match_path(
378 &Path::try_from(r#"{"People"}[2]{"Height"}"#).unwrap(),
379 ParsedKind::Num
380 ));
381 assert!(simple.match_path(
382 &Path::try_from(r#"{"People"}[3]{"Height"}"#).unwrap(),
383 ParsedKind::Num
384 ));
385 assert!(simple.match_path(
386 &Path::try_from(r#"{"People"}[4]{"Height"}"#).unwrap(),
387 ParsedKind::Num
388 ));
389 assert!(simple.match_path(
390 &Path::try_from(r#"{"People"}[5]{"Height"}"#).unwrap(),
391 ParsedKind::Num
392 ));
393 assert!(simple.match_path(
394 &Path::try_from(r#"{"People"}[6]{"Height"}"#).unwrap(),
395 ParsedKind::Num
396 ));
397 }
398
399 #[test]
400 fn wild_object() {
401 let simple = Simple::from_str(r#"{"People"}[0]{}"#).unwrap();
402
403 assert!(!simple.match_path(&Path::try_from(r#"{"People"}"#).unwrap(), ParsedKind::Arr));
404 assert!(!simple.match_path(
405 &Path::try_from(r#"{"People"}[0]"#).unwrap(),
406 ParsedKind::Obj
407 ));
408 assert!(simple.match_path(
409 &Path::try_from(r#"{"People"}[0]{"Age"}"#).unwrap(),
410 ParsedKind::Num
411 ));
412 assert!(simple.match_path(
413 &Path::try_from(r#"{"People"}[0]{"Height"}"#).unwrap(),
414 ParsedKind::Num
415 ));
416 assert!(!simple.match_path(
417 &Path::try_from(r#"{"People"}[1]"#).unwrap(),
418 ParsedKind::Obj
419 ));
420 assert!(!simple.match_path(
421 &Path::try_from(r#"{"People"}[1]{"Age"}"#).unwrap(),
422 ParsedKind::Num
423 ));
424 assert!(!simple.match_path(
425 &Path::try_from(r#"{"People"}[1]{"Height"}"#).unwrap(),
426 ParsedKind::Num
427 ));
428 }
429
430 #[test]
431 fn object_escapes() {
432 let simple = Simple::from_str(r#"{"People"}[0]{"\""}"#).unwrap();
433 assert!(simple.match_path(
434 &Path::try_from(r#"{"People"}[0]{"\""}"#).unwrap(),
435 ParsedKind::Num
436 ));
437 assert!(!simple.match_path(
438 &Path::try_from(r#"{"People"}[0]{""}"#).unwrap(),
439 ParsedKind::Num
440 ));
441 assert!(!simple.match_path(
442 &Path::try_from(r#"{"People"}[0]{"\"x"}"#).unwrap(),
443 ParsedKind::Num
444 ));
445 assert!(!simple.match_path(
446 &Path::try_from(r#"{"People"}[0]{"y\""}"#).unwrap(),
447 ParsedKind::Num
448 ));
449 }
450
451 #[test]
452 fn wild_object_escapes() {
453 let simple = Simple::from_str(r#"{"People"}[0]{}"#).unwrap();
454 assert!(simple.match_path(
455 &Path::try_from(r#"{"People"}[0]{"O\"ll"}"#).unwrap(),
456 ParsedKind::Num
457 ));
458 assert!(simple.match_path(
459 &Path::try_from(r#"{"People"}[0]{"O\\\"ll"}"#).unwrap(),
460 ParsedKind::Num
461 ));
462 }
463
464 #[test]
465 fn parse() {
466 assert!(Simple::from_str(r#""#).is_ok());
467 assert!(Simple::from_str(r#"{}"#).is_ok());
468 assert!(Simple::from_str(r#"{}[3]"#).is_ok());
469 assert!(Simple::from_str(r#"{"xx"}[]"#).is_ok());
470 assert!(Simple::from_str(r#"{}[]"#).is_ok());
471 assert!(Simple::from_str(r#"{"š𐍈€"}"#).is_ok());
472 assert!(Simple::from_str(r#"{"\""}"#).is_ok());
473 assert!(Simple::from_str(r#"[1,2,8,3-,-2,2-3]"#).is_ok());
474 assert!(Simple::from_str(r#"?"#).is_ok());
475 assert!(Simple::from_str(r#"????"#).is_ok());
476 assert!(Simple::from_str(r#"?{}[1]?{"xx"}"#).is_ok());
477 assert!(Simple::from_str(r#"*"#).is_ok());
478 assert!(Simple::from_str(r#"****"#).is_ok());
479 assert!(Simple::from_str(r#"*{}[1]**{"xx"}*"#).is_ok());
480 }
481
482 #[test]
483 fn parse_error() {
484 assert!(Simple::from_str(r#"{"People""#).is_err());
485 assert!(Simple::from_str(r#"[}"#).is_err());
486 assert!(Simple::from_str(r#"{"People}"#).is_err());
487 assert!(Simple::from_str(r#"{"š𐍈€""#).is_err());
488 assert!(Simple::from_str(r#"[1,2,8,3-,-2,-]"#).is_err());
489 assert!(Simple::from_str(r#"[3-3]"#).is_err());
490 assert!(Simple::from_str(r#"[,2,8]"#).is_err());
491 assert!(Simple::from_str(r#"[2,8,]"#).is_err());
492 }
493
494 #[test]
495 fn single_wild() {
496 let simple = Simple::from_str(r#"?[0]{"range"}?"#).unwrap();
497
498 assert!(simple.match_path(
499 &Path::try_from(r#"[1][0]{"range"}{"from_home"}"#).unwrap(),
500 ParsedKind::Num
501 ));
502 assert!(simple.match_path(
503 &Path::try_from(r#"{"People"}[0]{"range"}[1]"#).unwrap(),
504 ParsedKind::Num
505 ));
506 assert!(!simple.match_path(
507 &Path::try_from(r#"[0]{"range"}{"from_home"}"#).unwrap(),
508 ParsedKind::Num
509 ));
510 assert!(!simple.match_path(
511 &Path::try_from(r#"{"People"}[0]{"range"}"#).unwrap(),
512 ParsedKind::Arr
513 ));
514 assert!(!simple.match_path(
515 &Path::try_from(r#"{"People"}[1]{"range"}[1]"#).unwrap(),
516 ParsedKind::Num
517 ));
518 assert!(!simple.match_path(
519 &Path::try_from(r#"[1][0]{"other"}{"from_home"}"#).unwrap(),
520 ParsedKind::Num
521 ));
522 }
523
524 #[test]
525 fn any_wild() {
526 let simple = Simple::from_str(r#"*[0]*{"range"}**"#).unwrap();
527
528 assert!(simple.match_path(&Path::try_from(r#"[0]{"range"}"#).unwrap(), ParsedKind::Obj));
529 assert!(simple.match_path(
530 &Path::try_from(r#"[1][0]{"range"}{"from_home"}"#).unwrap(),
531 ParsedKind::Obj
532 ));
533 assert!(simple.match_path(
534 &Path::try_from(r#"{"another"}[1][0]{"range"}{"from_home"}[2]"#).unwrap(),
535 ParsedKind::Obj
536 ));
537 assert!(simple.match_path(
538 &Path::try_from(r#"[0][2]{"range"}"#).unwrap(),
539 ParsedKind::Obj
540 ));
541 assert!(simple.match_path(
542 &Path::try_from(r#"[0]{"middle"}{"range"}"#).unwrap(),
543 ParsedKind::Obj
544 ));
545 assert!(!simple.match_path(&Path::try_from(r#"[1]{"range"}"#).unwrap(), ParsedKind::Obj));
546 assert!(!simple.match_path(&Path::try_from(r#"[0]{"other"}"#).unwrap(), ParsedKind::Obj));
547 }
548}