streamson_lib/matcher/
combinator.rs1use std::{ops, sync::Arc};
4
5use super::Matcher;
6use crate::{path::Path, streamer::ParsedKind};
7
8#[derive(Debug, Clone)]
9pub enum Combinator {
16 Matcher(Arc<dyn Matcher + Sync>),
18 Not(Box<Combinator>),
20 And(Box<Combinator>, Box<Combinator>),
22 Or(Box<Combinator>, Box<Combinator>),
24}
25
26impl Matcher for Combinator {
27 fn match_path(&self, path: &Path, kind: ParsedKind) -> bool {
28 match self {
29 Self::Matcher(matcher) => matcher.match_path(path, kind),
30 Self::Not(combinator) => !combinator.match_path(path, kind),
31 Self::Or(first, second) => {
32 first.match_path(path, kind) || second.match_path(path, kind)
33 }
34 Self::And(first, second) => {
35 first.match_path(path, kind) && second.match_path(path, kind)
36 }
37 }
38 }
39}
40
41impl Combinator {
42 pub fn new(matcher: impl Matcher + 'static + Sync) -> Self {
47 Self::Matcher(Arc::new(matcher))
48 }
49}
50
51impl ops::Not for Combinator {
52 type Output = Self;
53
54 fn not(self) -> Self {
55 Self::Not(Box::new(self))
56 }
57}
58
59impl ops::BitAnd for Combinator {
60 type Output = Self;
61 fn bitand(self, rhs: Self) -> Self {
62 Self::And(Box::new(self), Box::new(rhs))
63 }
64}
65
66impl ops::BitOr for Combinator {
67 type Output = Self;
68 fn bitor(self, rhs: Self) -> Self {
69 Self::Or(Box::new(self), Box::new(rhs))
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::{Combinator, Matcher};
76 use crate::{
77 matcher::{Depth, Simple},
78 path::Path,
79 streamer::ParsedKind,
80 };
81 use std::convert::TryFrom;
82
83 #[test]
84 fn wrapper() {
85 let comb = Combinator::new(Depth::new(1, Some(1)));
86 assert!(comb.match_path(&Path::try_from(r#"{"People"}"#).unwrap(), ParsedKind::Arr));
87 assert!(comb.match_path(&Path::try_from(r#"[0]"#).unwrap(), ParsedKind::Obj));
88 }
89
90 #[test]
91 fn not() {
92 let comb = !Combinator::new(Depth::new(1, None));
93 assert!(!comb.match_path(&Path::try_from(r#"{"People"}"#).unwrap(), ParsedKind::Arr));
94 assert!(!comb.match_path(&Path::try_from(r#"[0]"#).unwrap(), ParsedKind::Obj));
95 assert!(comb.match_path(&Path::try_from(r#""#).unwrap(), ParsedKind::Obj));
96 assert!(!comb.match_path(
97 &Path::try_from(r#"{"People"}[0]"#).unwrap(),
98 ParsedKind::Obj
99 ));
100 }
101
102 #[test]
103 fn and() {
104 let comb = Combinator::new(Depth::new(1, Some(1)))
105 & Combinator::new(Simple::new(r#"{}"#).unwrap());
106 assert!(comb.match_path(&Path::try_from(r#"{"People"}"#).unwrap(), ParsedKind::Arr));
107 assert!(!comb.match_path(&Path::try_from(r#"[0]"#).unwrap(), ParsedKind::Obj));
108 assert!(!comb.match_path(&Path::try_from(r#""#).unwrap(), ParsedKind::Obj));
109 assert!(!comb.match_path(
110 &Path::try_from(r#"{"People"}[0]"#).unwrap(),
111 ParsedKind::Obj
112 ));
113 }
114
115 #[test]
116 fn or() {
117 let comb = Combinator::new(Depth::new(1, Some(1)))
118 | Combinator::new(Simple::new(r#"{}[0]"#).unwrap());
119 assert!(comb.match_path(&Path::try_from(r#"{"People"}"#).unwrap(), ParsedKind::Arr));
120 assert!(comb.match_path(&Path::try_from(r#"[0]"#).unwrap(), ParsedKind::Obj));
121 assert!(!comb.match_path(&Path::try_from(r#""#).unwrap(), ParsedKind::Obj));
122 assert!(comb.match_path(
123 &Path::try_from(r#"{"People"}[0]"#).unwrap(),
124 ParsedKind::Obj
125 ));
126 assert!(!comb.match_path(
127 &Path::try_from(r#"{"People"}[1]"#).unwrap(),
128 ParsedKind::Obj
129 ));
130 }
131
132 #[test]
133 fn complex() {
134 let comb1 = Combinator::new(Depth::new(1, Some(1)))
135 | Combinator::new(Simple::new(r#"{}[0]"#).unwrap());
136 let comb2 = Combinator::new(Depth::new(2, Some(2)))
137 | Combinator::new(Simple::new(r#"{}"#).unwrap());
138 let comb3 = !comb1 & comb2;
139
140 assert!(!comb3.match_path(&Path::try_from(r#"{"People"}"#).unwrap(), ParsedKind::Arr));
141 assert!(!comb3.match_path(&Path::try_from(r#"[0]"#).unwrap(), ParsedKind::Obj));
142 assert!(!comb3.match_path(&Path::try_from(r#""#).unwrap(), ParsedKind::Obj));
143 assert!(!comb3.match_path(
144 &Path::try_from(r#"{"People"}[0]"#).unwrap(),
145 ParsedKind::Obj
146 ));
147 assert!(comb3.match_path(
148 &Path::try_from(r#"{"People"}[1]"#).unwrap(),
149 ParsedKind::Obj
150 ));
151 }
152}