1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use super::MatchMaker;
use std::ops;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum Combinator {
Matcher(Arc<dyn MatchMaker + Sync>),
Not(Box<Combinator>),
And(Box<Combinator>, Box<Combinator>),
Or(Box<Combinator>, Box<Combinator>),
}
impl MatchMaker for Combinator {
fn match_path(&self, path: &str) -> bool {
match self {
Self::Matcher(matcher) => matcher.match_path(path),
Self::Not(combinator) => !combinator.match_path(path),
Self::Or(first, second) => first.match_path(path) || second.match_path(path),
Self::And(first, second) => first.match_path(path) && second.match_path(path),
}
}
}
impl Combinator {
pub fn new(matcher: impl MatchMaker + 'static + Sync) -> Self {
Self::Matcher(Arc::new(matcher))
}
}
impl ops::Not for Combinator {
type Output = Self;
fn not(self) -> Self {
Self::Not(Box::new(self))
}
}
impl ops::BitAnd for Combinator {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
Self::And(Box::new(self), Box::new(rhs))
}
}
impl ops::BitOr for Combinator {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self::Or(Box::new(self), Box::new(rhs))
}
}
#[cfg(test)]
mod tests {
use super::{Combinator, MatchMaker};
use crate::matcher::{Depth, Simple};
#[test]
fn wrapper() {
let comb = Combinator::new(Depth::new(1, Some(1)));
assert!(comb.match_path(r#"{"People"}"#));
assert!(comb.match_path(r#"[0]"#));
}
#[test]
fn not() {
let comb = !Combinator::new(Depth::new(1, None));
assert!(!comb.match_path(r#"{"People"}"#));
assert!(!comb.match_path(r#"[0]"#));
assert!(comb.match_path(r#""#));
assert!(!comb.match_path(r#"{"People"}[0]"#));
}
#[test]
fn and() {
let comb = Combinator::new(Depth::new(1, Some(1))) & Combinator::new(Simple::new(r#"{}"#));
assert!(comb.match_path(r#"{"People"}"#));
assert!(!comb.match_path(r#"[0]"#));
assert!(!comb.match_path(r#""#));
assert!(!comb.match_path(r#"{"People"}[0]"#));
}
#[test]
fn or() {
let comb =
Combinator::new(Depth::new(1, Some(1))) | Combinator::new(Simple::new(r#"{}[0]"#));
assert!(comb.match_path(r#"{"People"}"#));
assert!(comb.match_path(r#"[0]"#));
assert!(!comb.match_path(r#""#));
assert!(comb.match_path(r#"{"People"}[0]"#));
assert!(!comb.match_path(r#"{"People"}[1]"#));
}
#[test]
fn complex() {
let comb1 =
Combinator::new(Depth::new(1, Some(1))) | Combinator::new(Simple::new(r#"{}[0]"#));
let comb2 = Combinator::new(Depth::new(2, Some(2))) | Combinator::new(Simple::new(r#"{}"#));
let comb3 = !comb1 & comb2;
assert!(!comb3.match_path(r#"{"People"}"#));
assert!(!comb3.match_path(r#"[0]"#));
assert!(!comb3.match_path(r#""#));
assert!(!comb3.match_path(r#"{"People"}[0]"#));
assert!(comb3.match_path(r#"{"People"}[1]"#));
}
}