atc_router/
interpreter.rs

1use crate::ast::{BinaryOperator, Expression, LogicalExpression, Predicate, Value};
2use crate::context::{Context, Match};
3
4pub trait Execute {
5    fn execute(&self, ctx: &mut Context, m: &mut Match) -> bool;
6}
7
8impl Execute for Expression {
9    fn execute(&self, ctx: &mut Context, m: &mut Match) -> bool {
10        match self {
11            Expression::Logical(l) => match l.as_ref() {
12                LogicalExpression::And(l, r) => l.execute(ctx, m) && r.execute(ctx, m),
13                LogicalExpression::Or(l, r) => l.execute(ctx, m) || r.execute(ctx, m),
14                LogicalExpression::Not(r) => !r.execute(ctx, m),
15            },
16            Expression::Predicate(p) => p.execute(ctx, m),
17        }
18    }
19}
20
21impl Execute for Predicate {
22    fn execute(&self, ctx: &mut Context, m: &mut Match) -> bool {
23        let lhs_values = match ctx.value_of(&self.lhs.var_name) {
24            None => return false,
25            Some(v) => v,
26        };
27
28        let (lower, any) = self.lhs.get_transformations();
29
30        // can only be "all" or "any" mode.
31        // - all: all values must match (default)
32        // - any: ok if any any matched
33        for mut lhs_value in lhs_values.iter() {
34            let lhs_value_transformed;
35
36            if lower {
37                match lhs_value {
38                    Value::String(s) => {
39                        lhs_value_transformed = Value::String(s.to_lowercase());
40                        lhs_value = &lhs_value_transformed;
41                    }
42                    _ => unreachable!(),
43                }
44            }
45
46            let mut matched = false;
47            match self.op {
48                BinaryOperator::Equals => {
49                    if lhs_value == &self.rhs {
50                        m.matches
51                            .insert(self.lhs.var_name.clone(), self.rhs.clone());
52
53                        if any {
54                            return true;
55                        }
56
57                        matched = true;
58                    }
59                }
60                BinaryOperator::NotEquals => {
61                    if lhs_value != &self.rhs {
62                        if any {
63                            return true;
64                        }
65
66                        matched = true;
67                    }
68                }
69                BinaryOperator::Regex => {
70                    let rhs = match &self.rhs {
71                        Value::Regex(r) => r,
72                        _ => unreachable!(),
73                    };
74                    let lhs = match lhs_value {
75                        Value::String(s) => s,
76                        _ => unreachable!(),
77                    };
78
79                    if rhs.is_match(lhs) {
80                        let reg_cap = rhs.captures(lhs).unwrap();
81
82                        m.matches.insert(
83                            self.lhs.var_name.clone(),
84                            Value::String(reg_cap.get(0).unwrap().as_str().to_string()),
85                        );
86
87                        for (i, c) in reg_cap.iter().enumerate() {
88                            if let Some(c) = c {
89                                m.captures.insert(i.to_string(), c.as_str().to_string());
90                            }
91                        }
92
93                        // named captures
94                        for n in rhs.capture_names().flatten() {
95                            if let Some(value) = reg_cap.name(n) {
96                                m.captures.insert(n.to_string(), value.as_str().to_string());
97                            }
98                        }
99
100                        if any {
101                            return true;
102                        }
103
104                        matched = true;
105                    }
106                }
107                BinaryOperator::Prefix => {
108                    let rhs = match &self.rhs {
109                        Value::String(s) => s,
110                        _ => unreachable!(),
111                    };
112                    let lhs = match lhs_value {
113                        Value::String(s) => s,
114                        _ => unreachable!(),
115                    };
116
117                    if lhs.starts_with(rhs) {
118                        m.matches
119                            .insert(self.lhs.var_name.clone(), self.rhs.clone());
120                        if any {
121                            return true;
122                        }
123
124                        matched = true;
125                    }
126                }
127                BinaryOperator::Postfix => {
128                    let rhs = match &self.rhs {
129                        Value::String(s) => s,
130                        _ => unreachable!(),
131                    };
132                    let lhs = match lhs_value {
133                        Value::String(s) => s,
134                        _ => unreachable!(),
135                    };
136
137                    if lhs.ends_with(rhs) {
138                        m.matches
139                            .insert(self.lhs.var_name.clone(), self.rhs.clone());
140                        if any {
141                            return true;
142                        }
143
144                        matched = true;
145                    }
146                }
147                BinaryOperator::Greater => {
148                    let rhs = match &self.rhs {
149                        Value::Int(i) => i,
150                        _ => unreachable!(),
151                    };
152                    let lhs = match lhs_value {
153                        Value::Int(i) => i,
154                        _ => unreachable!(),
155                    };
156
157                    if lhs > rhs {
158                        if any {
159                            return true;
160                        }
161
162                        matched = true;
163                    }
164                }
165                BinaryOperator::GreaterOrEqual => {
166                    let rhs = match &self.rhs {
167                        Value::Int(i) => i,
168                        _ => unreachable!(),
169                    };
170                    let lhs = match lhs_value {
171                        Value::Int(i) => i,
172                        _ => unreachable!(),
173                    };
174
175                    if lhs >= rhs {
176                        if any {
177                            return true;
178                        }
179
180                        matched = true;
181                    }
182                }
183                BinaryOperator::Less => {
184                    let rhs = match &self.rhs {
185                        Value::Int(i) => i,
186                        _ => unreachable!(),
187                    };
188                    let lhs = match lhs_value {
189                        Value::Int(i) => i,
190                        _ => unreachable!(),
191                    };
192
193                    if lhs < rhs {
194                        if any {
195                            return true;
196                        }
197
198                        matched = true;
199                    }
200                }
201                BinaryOperator::LessOrEqual => {
202                    let rhs = match &self.rhs {
203                        Value::Int(i) => i,
204                        _ => unreachable!(),
205                    };
206                    let lhs = match lhs_value {
207                        Value::Int(i) => i,
208                        _ => unreachable!(),
209                    };
210
211                    if lhs <= rhs {
212                        if any {
213                            return true;
214                        }
215
216                        matched = true;
217                    }
218                }
219                BinaryOperator::In => match (lhs_value, &self.rhs) {
220                    (Value::IpAddr(l), Value::IpCidr(r)) => {
221                        if r.contains(l) {
222                            matched = true;
223                            if any {
224                                return true;
225                            }
226                        }
227                    }
228                    _ => unreachable!(),
229                },
230                BinaryOperator::NotIn => match (lhs_value, &self.rhs) {
231                    (Value::IpAddr(l), Value::IpCidr(r)) => {
232                        if !r.contains(l) {
233                            matched = true;
234                            if any {
235                                return true;
236                            }
237                        }
238                    }
239                    _ => unreachable!(),
240                },
241                BinaryOperator::Contains => {
242                    let rhs = match &self.rhs {
243                        Value::String(s) => s,
244                        _ => unreachable!(),
245                    };
246                    let lhs = match lhs_value {
247                        Value::String(s) => s,
248                        _ => unreachable!(),
249                    };
250
251                    if lhs.contains(rhs) {
252                        if any {
253                            return true;
254                        }
255
256                        matched = true;
257                    }
258                }
259            } // match
260
261            if !any && !matched {
262                // all and nothing matched
263                return false;
264            }
265        } // for iter
266
267        // if we reached here, it means that `any` did not find a match,
268        // or we passed all matches for `all`. So we simply need to return
269        // !any && lhs_values.len() > 0 to cover both cases
270        !any && !lhs_values.is_empty()
271    }
272}
273
274#[test]
275fn test_predicate() {
276    use crate::ast;
277    use crate::schema;
278
279    let mut mat = Match::new();
280    let mut schema = schema::Schema::default();
281    schema.add_field("my_key", ast::Type::String);
282    let mut ctx = Context::new(&schema);
283
284    // check when value list is empty
285    // check if all values match starts_with foo -- should be false
286    let p = Predicate {
287        lhs: ast::Lhs {
288            var_name: "my_key".to_string(),
289            transformations: vec![],
290        },
291        rhs: Value::String("foo".to_string()),
292        op: BinaryOperator::Prefix,
293    };
294
295    assert_eq!(p.execute(&mut ctx, &mut mat), false);
296
297    // check if any value matches starts_with foo -- should be false
298    let p = Predicate {
299        lhs: ast::Lhs {
300            var_name: "my_key".to_string(),
301            transformations: vec![],
302        },
303        rhs: Value::String("foo".to_string()),
304        op: BinaryOperator::Prefix,
305    };
306
307    assert_eq!(p.execute(&mut ctx, &mut mat), false);
308
309    // test any mode
310    let lhs_values = vec![
311        Value::String("foofoo".to_string()),
312        Value::String("foobar".to_string()),
313        Value::String("foocar".to_string()),
314        Value::String("fooban".to_string()),
315    ];
316
317    for v in lhs_values {
318        ctx.add_value("my_key", v);
319    }
320
321    // check if all values match starts_with foo -- should be true
322    let p = Predicate {
323        lhs: ast::Lhs {
324            var_name: "my_key".to_string(),
325            transformations: vec![],
326        },
327        rhs: Value::String("foo".to_string()),
328        op: BinaryOperator::Prefix,
329    };
330
331    assert_eq!(p.execute(&mut ctx, &mut mat), true);
332
333    // check if all values match ends_with foo -- should be false
334    let p = Predicate {
335        lhs: ast::Lhs {
336            var_name: "my_key".to_string(),
337            transformations: vec![],
338        },
339        rhs: Value::String("foo".to_string()),
340        op: BinaryOperator::Postfix,
341    };
342
343    assert_eq!(p.execute(&mut ctx, &mut mat), false);
344
345    // check if any value matches ends_with foo -- should be true
346    let p = Predicate {
347        lhs: ast::Lhs {
348            var_name: "my_key".to_string(),
349            transformations: vec![ast::LhsTransformations::Any],
350        },
351        rhs: Value::String("foo".to_string()),
352        op: BinaryOperator::Postfix,
353    };
354
355    assert_eq!(p.execute(&mut ctx, &mut mat), true);
356
357    // check if any value matches starts_with foo -- should be true
358    let p = Predicate {
359        lhs: ast::Lhs {
360            var_name: "my_key".to_string(),
361            transformations: vec![ast::LhsTransformations::Any],
362        },
363        rhs: Value::String("foo".to_string()),
364        op: BinaryOperator::Prefix,
365    };
366
367    assert_eq!(p.execute(&mut ctx, &mut mat), true);
368
369    // check if any value matches ends_with nar -- should be false
370    let p = Predicate {
371        lhs: ast::Lhs {
372            var_name: "my_key".to_string(),
373            transformations: vec![ast::LhsTransformations::Any],
374        },
375        rhs: Value::String("nar".to_string()),
376        op: BinaryOperator::Postfix,
377    };
378
379    assert_eq!(p.execute(&mut ctx, &mut mat), false);
380
381    // check if any value matches ends_with empty string -- should be true
382    let p = Predicate {
383        lhs: ast::Lhs {
384            var_name: "my_key".to_string(),
385            transformations: vec![ast::LhsTransformations::Any],
386        },
387        rhs: Value::String("".to_string()),
388        op: BinaryOperator::Postfix,
389    };
390
391    assert_eq!(p.execute(&mut ctx, &mut mat), true);
392
393    // check if any value matches starts_with empty string -- should be true
394    let p = Predicate {
395        lhs: ast::Lhs {
396            var_name: "my_key".to_string(),
397            transformations: vec![ast::LhsTransformations::Any],
398        },
399        rhs: Value::String("".to_string()),
400        op: BinaryOperator::Prefix,
401    };
402
403    assert_eq!(p.execute(&mut ctx, &mut mat), true);
404
405    // check if any value matches contains `ob` -- should be true
406    let p = Predicate {
407        lhs: ast::Lhs {
408            var_name: "my_key".to_string(),
409            transformations: vec![ast::LhsTransformations::Any],
410        },
411        rhs: Value::String("ob".to_string()),
412        op: BinaryOperator::Contains,
413    };
414
415    assert_eq!(p.execute(&mut ctx, &mut mat), true);
416
417    // check if any value matches contains `ok` -- should be false
418    let p = Predicate {
419        lhs: ast::Lhs {
420            var_name: "my_key".to_string(),
421            transformations: vec![ast::LhsTransformations::Any],
422        },
423        rhs: Value::String("ok".to_string()),
424        op: BinaryOperator::Contains,
425    };
426
427    assert_eq!(p.execute(&mut ctx, &mut mat), false);
428}