tau_engine/
solver.rs

1use std::collections::HashMap;
2use std::fmt;
3
4use aho_corasick::AhoCorasick;
5use tracing::debug;
6
7use crate::document::Document;
8use crate::parser::{Expression, Match, MatchType, Search};
9use crate::rule::Detection;
10use crate::tokeniser::{BoolSym, ModSym};
11use crate::value::Value;
12
13struct Cache<'a>(&'a Vec<Option<Value<'a>>>);
14
15impl<'a> Document for Cache<'a> {
16    fn find(&self, key: &str) -> Option<Value> {
17        let i = key.chars().nth(0).expect("could not get key") as u32;
18        self.0[i as usize].clone()
19    }
20}
21
22struct Passthrough<'a>(Option<Value<'a>>);
23
24impl<'a> Document for Passthrough<'a> {
25    fn find(&self, _: &str) -> Option<Value> {
26        self.0.clone()
27    }
28}
29
30#[derive(Debug, PartialEq)]
31pub(crate) enum SolverResult {
32    True,
33    False,
34    Missing,
35}
36impl fmt::Display for SolverResult {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        match self {
39            Self::True => write!(f, "true"),
40            Self::False => write!(f, "false"),
41            Self::Missing => write!(f, "missing"),
42        }
43    }
44}
45
46/// Evalutes a `Document` with a provided detection, returning true if the detection solves.
47pub fn solve(detection: &Detection, document: &dyn Document) -> bool {
48    match solve_expression(&detection.expression, &detection.identifiers, document) {
49        SolverResult::True => true,
50        SolverResult::False | SolverResult::Missing => false,
51    }
52}
53
54pub(crate) fn solve_expression(
55    expression: &Expression,
56    identifiers: &HashMap<String, Expression>,
57    document: &dyn Document,
58) -> SolverResult {
59    match *expression {
60        Expression::BooleanGroup(BoolSym::And, ref group) => {
61            for expression in group {
62                match solve_expression(expression, identifiers, document) {
63                    SolverResult::True => {}
64                    SolverResult::False => return SolverResult::False,
65                    SolverResult::Missing => return SolverResult::Missing,
66                }
67            }
68            SolverResult::True
69        }
70        Expression::BooleanGroup(BoolSym::Or, ref group) => {
71            let mut res = SolverResult::Missing;
72            for expression in group {
73                match solve_expression(expression, identifiers, document) {
74                    SolverResult::True => return SolverResult::True,
75                    SolverResult::False => res = SolverResult::False,
76                    SolverResult::Missing => {}
77                }
78            }
79            res
80        }
81        Expression::BooleanExpression(ref left, ref op, ref right) => {
82            // Edge cases
83            match (&**left, op, &**right) {
84                (
85                    Expression::Cast(left, ModSym::Str),
86                    BoolSym::Equal,
87                    Expression::Cast(right, ModSym::Str),
88                ) => {
89                    let x = match document.find(left) {
90                        Some(x) => x,
91                        None => {
92                            debug!("evaluating missing, no left hand side for {}", expression);
93                            return SolverResult::Missing;
94                        }
95                    };
96                    let x = match x.to_string() {
97                        Some(v) => v,
98                        None => {
99                            debug!(
100                                "evaluating false, could not cast left field to string for {}",
101                                expression
102                            );
103                            return SolverResult::False;
104                        }
105                    };
106                    let y = match document.find(right) {
107                        Some(x) => x,
108                        None => {
109                            debug!("evaluating missing, no right hand side for {}", expression);
110                            return SolverResult::Missing;
111                        }
112                    };
113                    let y = match y.to_string() {
114                        Some(v) => v,
115                        None => {
116                            debug!(
117                                "evaluating false, could not cast right field to string for {}",
118                                expression
119                            );
120                            return SolverResult::False;
121                        }
122                    };
123                    if x == y {
124                        return SolverResult::True;
125                    } else {
126                        return SolverResult::False;
127                    }
128                }
129                (Expression::Field(left), BoolSym::Equal, Expression::Boolean(b)) => {
130                    let x = match document.find(left) {
131                        Some(x) => x,
132                        None => {
133                            debug!("evaluating missing, no left hand side for {}", expression);
134                            return SolverResult::Missing;
135                        }
136                    };
137                    let x = match x.as_bool() {
138                        Some(v) => v,
139                        None => {
140                            debug!(
141                                "evaluating false, could not cast left field to boolean for {}",
142                                expression
143                            );
144                            return SolverResult::False;
145                        }
146                    };
147                    if x == *b {
148                        return SolverResult::True;
149                    } else {
150                        return SolverResult::False;
151                    }
152                }
153                (Expression::Field(left), BoolSym::Equal, Expression::Null) => {
154                    let x = match document.find(left) {
155                        Some(x) => x,
156                        None => {
157                            debug!("evaluating missing, no left hand side for {}", expression);
158                            return SolverResult::Missing;
159                        }
160                    };
161                    if x.is_null() {
162                        return SolverResult::True;
163                    } else {
164                        return SolverResult::False;
165                    }
166                }
167                _ => {}
168            }
169            // Boolean expressions
170            match *op {
171                BoolSym::Equal
172                | BoolSym::GreaterThan
173                | BoolSym::GreaterThanOrEqual
174                | BoolSym::LessThan
175                | BoolSym::LessThanOrEqual => {
176                    let x = match left.as_ref() {
177                        Expression::Field(f) => {
178                            let i = match document.find(f) {
179                                Some(i) => i,
180                                None => {
181                                    debug!(
182                                        "evaluating missing, no left hand side for {}",
183                                        expression
184                                    );
185                                    return SolverResult::Missing;
186                                }
187                            };
188                            match i {
189                                Value::Float(_) | Value::Int(_) | Value::UInt(_) => i,
190                                _ => {
191                                    debug!(
192                                        "evaluating false, no left hand side for {}",
193                                        expression
194                                    );
195                                    return SolverResult::False;
196                                }
197                            }
198                        }
199                        Expression::Cast(field, ModSym::Flt) => {
200                            let i = match document.find(field) {
201                                Some(i) => i,
202                                None => {
203                                    debug!(
204                                        "evaluating missing, no left hand side for {}",
205                                        expression
206                                    );
207                                    return SolverResult::Missing;
208                                }
209                            };
210                            match i {
211                                Value::Bool(x) => {
212                                    if x {
213                                        Value::Float(1.0)
214                                    } else {
215                                        Value::Float(1.0)
216                                    }
217                                }
218                                Value::Float(x) => Value::Float(x),
219                                Value::Int(x) => {
220                                    if x <= f64::MAX as i64 {
221                                        Value::Float(x as f64)
222                                    } else {
223                                        debug!(
224                                            "evaluating false, could not cast left hand side for {} - {}",
225                                            expression, x
226                                        );
227                                        return SolverResult::False;
228                                    }
229                                }
230                                Value::String(x) => match x.parse::<f64>() {
231                                    Ok(i) => Value::Float(i),
232                                    Err(e) => {
233                                        debug!(
234                                            "evaluating false, could not cast left hand side for {} - {}",
235                                            expression, e
236                                        );
237                                        return SolverResult::False;
238                                    }
239                                },
240                                Value::UInt(x) => {
241                                    if x <= f64::MAX as u64 {
242                                        Value::Float(x as f64)
243                                    } else {
244                                        debug!(
245                                            "evaluating false, could not cast left hand side for {} - {}",
246                                            expression, x
247                                        );
248                                        return SolverResult::False;
249                                    }
250                                }
251                                _ => {
252                                    debug!(
253                                        "evaluating false, invalid type on left hand side for {}",
254                                        expression
255                                    );
256                                    return SolverResult::False;
257                                }
258                            }
259                        }
260                        Expression::Cast(field, ModSym::Int) => {
261                            let i = match document.find(field) {
262                                Some(i) => i,
263                                None => {
264                                    debug!(
265                                        "evaluating missing, no left hand side for {}",
266                                        expression
267                                    );
268                                    return SolverResult::Missing;
269                                }
270                            };
271                            match i {
272                                Value::Bool(x) => {
273                                    if x {
274                                        Value::Int(1)
275                                    } else {
276                                        Value::Int(0)
277                                    }
278                                }
279                                Value::Float(x) => Value::Int(x.round() as i64),
280                                Value::Int(x) => Value::Int(x),
281                                Value::String(x) => match x.parse::<i64>() {
282                                    Ok(i) => Value::Int(i),
283                                    Err(e) => {
284                                        debug!(
285                                            "evaluating false, could not cast left hand side for {} - {}",
286                                            expression, e
287                                        );
288                                        return SolverResult::False;
289                                    }
290                                },
291                                Value::UInt(x) => {
292                                    if x <= i64::MAX as u64 {
293                                        Value::Int(x as i64)
294                                    } else {
295                                        debug!(
296                                            "evaluating false, could not cast left hand side for {} - {}",
297                                            expression, x
298                                        );
299                                        return SolverResult::False;
300                                    }
301                                }
302                                _ => {
303                                    debug!(
304                                        "evaluating false, invalid type on left hand side for {}",
305                                        expression
306                                    );
307                                    return SolverResult::False;
308                                }
309                            }
310                        }
311                        Expression::Boolean(i) => Value::Bool(*i),
312                        Expression::Float(i) => Value::Float(*i),
313                        Expression::Integer(i) => Value::Int(*i),
314                        _ => {
315                            debug!("encountered invalid left hand side for {}", expression);
316                            return SolverResult::False;
317                        }
318                    };
319                    let y = match right.as_ref() {
320                        Expression::Field(f) => {
321                            let i = match document.find(f) {
322                                Some(i) => i,
323                                None => {
324                                    debug!(
325                                        "evaluating missing, no right hand side for {}",
326                                        expression
327                                    );
328                                    return SolverResult::Missing;
329                                }
330                            };
331                            match i {
332                                Value::Float(_) | Value::Int(_) | Value::UInt(_) => i,
333                                _ => {
334                                    debug!(
335                                        "evaluating false, no right hand side for {}",
336                                        expression
337                                    );
338                                    return SolverResult::False;
339                                }
340                            }
341                        }
342                        Expression::Cast(field, ModSym::Flt) => {
343                            let i = match document.find(field) {
344                                Some(i) => i,
345                                None => {
346                                    debug!(
347                                        "evaluating missing, no right hand side for {}",
348                                        expression
349                                    );
350                                    return SolverResult::Missing;
351                                }
352                            };
353                            match i {
354                                Value::Bool(x) => {
355                                    if x {
356                                        Value::Float(1.0)
357                                    } else {
358                                        Value::Float(1.0)
359                                    }
360                                }
361                                Value::Float(x) => Value::Float(x),
362                                Value::Int(x) => {
363                                    if x <= f64::MAX as i64 {
364                                        Value::Float(x as f64)
365                                    } else {
366                                        debug!(
367                                            "evaluating false, could not cast right hand side for {} - {}",
368                                            expression, x
369                                        );
370                                        return SolverResult::False;
371                                    }
372                                }
373                                Value::String(x) => match x.parse::<f64>() {
374                                    Ok(i) => Value::Float(i),
375                                    Err(e) => {
376                                        debug!(
377                                            "evaluating false, could not cast right hand side for {} - {}",
378                                            expression, e
379                                        );
380                                        return SolverResult::False;
381                                    }
382                                },
383                                Value::UInt(x) => {
384                                    if x <= f64::MAX as u64 {
385                                        Value::Float(x as f64)
386                                    } else {
387                                        debug!(
388                                            "evaluating false, could not cast right hand side for {} - {}",
389                                            expression, x
390                                        );
391                                        return SolverResult::False;
392                                    }
393                                }
394                                _ => {
395                                    debug!(
396                                        "evaluating false, invalid type on right hand side for {}",
397                                        expression
398                                    );
399                                    return SolverResult::False;
400                                }
401                            }
402                        }
403                        Expression::Cast(field, ModSym::Int) => {
404                            let i = match document.find(field) {
405                                Some(i) => i,
406                                None => {
407                                    debug!(
408                                        "evaluating missing, no right hand side for {}",
409                                        expression
410                                    );
411                                    return SolverResult::Missing;
412                                }
413                            };
414                            match i {
415                                Value::Bool(x) => {
416                                    if x {
417                                        Value::Int(1)
418                                    } else {
419                                        Value::Int(0)
420                                    }
421                                }
422                                Value::Float(x) => Value::Int(x.round() as i64),
423                                Value::Int(x) => Value::Int(x),
424                                Value::String(x) => match x.parse::<i64>() {
425                                    Ok(i) => Value::Int(i),
426                                    Err(e) => {
427                                        debug!(
428                                            "evaluating false, could not cast right hand side for {} - {}",
429                                            expression, e
430                                        );
431                                        return SolverResult::False;
432                                    }
433                                },
434                                Value::UInt(x) => {
435                                    if x <= i64::MAX as u64 {
436                                        Value::Int(x as i64)
437                                    } else {
438                                        debug!(
439                                            "evaluating false, could not cast right hand side for {} - {}",
440                                            expression, x
441                                        );
442                                        return SolverResult::False;
443                                    }
444                                }
445                                _ => {
446                                    debug!(
447                                        "evaluating false, invalid type on right hand side for {}",
448                                        expression
449                                    );
450                                    return SolverResult::False;
451                                }
452                            }
453                        }
454                        Expression::Boolean(i) => Value::Bool(*i),
455                        Expression::Float(i) => Value::Float(*i),
456                        Expression::Integer(i) => Value::Int(*i),
457                        _ => {
458                            debug!("encountered invalid right hand side for {}", expression);
459                            return SolverResult::False;
460                        }
461                    };
462                    let res = match (x, *op, y) {
463                        (Value::Bool(x), BoolSym::Equal, Value::Bool(y)) => x == y,
464                        (Value::Float(x), BoolSym::Equal, Value::Float(y)) => x == y,
465                        (Value::Int(x), BoolSym::Equal, Value::Int(y)) => x == y,
466                        (Value::UInt(x), BoolSym::Equal, Value::UInt(y)) => x == y,
467                        (Value::UInt(x), BoolSym::Equal, Value::Int(y)) if x <= i64::MAX as u64 => {
468                            x as i64 == y
469                        }
470                        (Value::Int(x), BoolSym::Equal, Value::UInt(y)) if y <= i64::MAX as u64 => {
471                            x == y as i64
472                        }
473                        (_, BoolSym::Equal, _) => false,
474                        (Value::Float(x), BoolSym::GreaterThan, Value::Float(y)) => x > y,
475                        (Value::Int(x), BoolSym::GreaterThan, Value::Int(y)) => x > y,
476                        (Value::UInt(x), BoolSym::GreaterThan, Value::UInt(y)) => x > y,
477                        (Value::UInt(x), BoolSym::GreaterThan, Value::Int(y))
478                            if x <= i64::MAX as u64 =>
479                        {
480                            x as i64 > y
481                        }
482                        (Value::Int(x), BoolSym::GreaterThan, Value::UInt(y))
483                            if y <= i64::MAX as u64 =>
484                        {
485                            x > y as i64
486                        }
487                        (_, BoolSym::GreaterThan, _) => false,
488                        (Value::Float(x), BoolSym::GreaterThanOrEqual, Value::Float(y)) => x >= y,
489                        (Value::Int(x), BoolSym::GreaterThanOrEqual, Value::Int(y)) => x >= y,
490                        (Value::UInt(x), BoolSym::GreaterThanOrEqual, Value::UInt(y)) => x >= y,
491                        (Value::UInt(x), BoolSym::GreaterThanOrEqual, Value::Int(y))
492                            if x <= i64::MAX as u64 =>
493                        {
494                            x as i64 >= y
495                        }
496                        (Value::Int(x), BoolSym::GreaterThanOrEqual, Value::UInt(y))
497                            if y <= i64::MAX as u64 =>
498                        {
499                            x >= y as i64
500                        }
501                        (_, BoolSym::GreaterThanOrEqual, _) => false,
502                        (Value::Float(x), BoolSym::LessThan, Value::Float(y)) => x < y,
503                        (Value::Int(x), BoolSym::LessThan, Value::Int(y)) => x < y,
504                        (Value::UInt(x), BoolSym::LessThan, Value::UInt(y)) => x < y,
505                        (Value::UInt(x), BoolSym::LessThan, Value::Int(y))
506                            if x <= i64::MAX as u64 =>
507                        {
508                            (x as i64) < y
509                        }
510                        (Value::Int(x), BoolSym::LessThan, Value::UInt(y))
511                            if y <= i64::MAX as u64 =>
512                        {
513                            x < y as i64
514                        }
515                        (_, BoolSym::LessThan, _) => false,
516                        (Value::Float(x), BoolSym::LessThanOrEqual, Value::Float(y)) => x <= y,
517                        (Value::Int(x), BoolSym::LessThanOrEqual, Value::Int(y)) => x <= y,
518                        (Value::UInt(x), BoolSym::LessThanOrEqual, Value::UInt(y)) => x <= y,
519                        (Value::UInt(x), BoolSym::LessThanOrEqual, Value::Int(y))
520                            if x <= i64::MAX as u64 =>
521                        {
522                            x as i64 <= y
523                        }
524                        (Value::Int(x), BoolSym::LessThanOrEqual, Value::UInt(y))
525                            if y <= i64::MAX as u64 =>
526                        {
527                            x <= y as i64
528                        }
529                        (_, BoolSym::LessThanOrEqual, _) => false,
530                        _ => unreachable!(),
531                    };
532                    match res {
533                        true => SolverResult::True,
534                        _ => SolverResult::False,
535                    }
536                }
537                BoolSym::And => {
538                    let x = match solve_expression(&*left, identifiers, document) {
539                        SolverResult::True => (true, false),
540                        SolverResult::False => return SolverResult::False,
541                        SolverResult::Missing => return SolverResult::Missing,
542                    };
543                    let y = match solve_expression(&*right, identifiers, document) {
544                        SolverResult::True => (true, false),
545                        SolverResult::False => (false, false),
546                        SolverResult::Missing => (false, true),
547                    };
548                    debug!(
549                        "evaluating {} ({}) for {}",
550                        x.0 && y.0,
551                        x.1 || y.1,
552                        expression
553                    );
554                    if x.1 || y.1 {
555                        SolverResult::Missing
556                    } else if x.0 && y.0 {
557                        SolverResult::True
558                    } else {
559                        SolverResult::False
560                    }
561                }
562                BoolSym::Or => {
563                    let x = match solve_expression(&*left, identifiers, document) {
564                        SolverResult::True => return SolverResult::True,
565                        SolverResult::False => (false, false),
566                        SolverResult::Missing => (false, true),
567                    };
568                    let y = match solve_expression(&*right, identifiers, document) {
569                        SolverResult::True => (true, false),
570                        SolverResult::False => (false, false),
571                        SolverResult::Missing => (false, true),
572                    };
573                    debug!(
574                        "evaluating {} ({}) for {}",
575                        x.0 || y.0,
576                        x.1 || y.1,
577                        expression
578                    );
579                    if x.0 || y.0 {
580                        SolverResult::True
581                    } else if x.1 && y.1 {
582                        SolverResult::Missing
583                    } else {
584                        SolverResult::False
585                    }
586                }
587            }
588        }
589        Expression::Identifier(ref i) => match identifiers.get(i) {
590            Some(e) => solve_expression(e, identifiers, document),
591            None => unreachable!(),
592        },
593        Expression::Match(Match::All, ref e) => {
594            let (_, group) = match **e {
595                Expression::Identifier(ref i) => match identifiers.get(i) {
596                    Some(Expression::BooleanGroup(o, g)) => (o, g),
597                    Some(e) => return match_all(e, identifiers, document),
598                    _ => unreachable!(),
599                },
600                Expression::BooleanGroup(ref o, ref g) => (o, g),
601                _ => return match_all(e, identifiers, document),
602            };
603            for expression in group {
604                match solve_expression(expression, identifiers, document) {
605                    SolverResult::True => {}
606                    SolverResult::False => return SolverResult::False,
607                    SolverResult::Missing => return SolverResult::Missing,
608                }
609            }
610            SolverResult::True
611        }
612        Expression::Match(Match::Of(c), ref e) => {
613            let (_, group) = match **e {
614                Expression::Identifier(ref identifier) => match identifiers.get(identifier) {
615                    Some(Expression::BooleanGroup(o, g)) => (o, g),
616                    Some(e) => return match_of(e, identifiers, document, c),
617                    _ => {
618                        unreachable!();
619                    }
620                },
621                Expression::BooleanGroup(ref o, ref g) => (o, g),
622                _ => return match_of(e, identifiers, document, c),
623            };
624            let mut count = 0;
625            let mut res = SolverResult::Missing;
626            for expression in group {
627                if c == 0 {
628                    match solve_expression(expression, identifiers, document) {
629                        SolverResult::True => return SolverResult::False,
630                        SolverResult::False => {
631                            res = SolverResult::True;
632                        }
633                        SolverResult::Missing => {}
634                    }
635                } else {
636                    match solve_expression(expression, identifiers, document) {
637                        SolverResult::True => {
638                            count += 1;
639                            if count >= c {
640                                return SolverResult::True;
641                            }
642                        }
643                        SolverResult::False => res = SolverResult::False,
644                        SolverResult::Missing => {}
645                    }
646                }
647            }
648            res
649        }
650        Expression::Matrix(ref columns, ref rows) => {
651            // NOTE: Field and search widths must be the same or tau will panic, for now this is
652            // fine as only the optimiser can write this expression, and for those using core it is
653            // on them to ensure they don't break this. There are ways to lock this down and it
654            // could be done in the future...
655            let size = columns.len();
656            let mut cache: Vec<Option<Value>> = Vec::with_capacity(size);
657            for _ in 0..size {
658                cache.push(None);
659            }
660
661            let mut res = SolverResult::Missing;
662            for row in rows {
663                let mut hit = SolverResult::True;
664                for (i, expression) in row.iter().enumerate() {
665                    if let Some(expression) = expression {
666                        if cache[i].is_none() {
667                            let value = match document.find(&columns[i]) {
668                                Some(v) => v,
669                                None => {
670                                    debug!(
671                                        "evaluating missing, field not found for {}",
672                                        expression
673                                    );
674                                    hit = SolverResult::Missing;
675                                    break;
676                                }
677                            };
678                            let _ = std::mem::replace(&mut cache[i], Some(value));
679                        }
680                        match solve_expression(expression, identifiers, &Cache(&cache)) {
681                            SolverResult::True => {}
682                            SolverResult::False => {
683                                hit = SolverResult::False;
684                                break;
685                            }
686                            SolverResult::Missing => {
687                                hit = SolverResult::Missing;
688                                break;
689                            }
690                        }
691                    }
692                }
693                match hit {
694                    SolverResult::True => return SolverResult::True,
695                    SolverResult::False => res = SolverResult::False,
696                    SolverResult::Missing => {}
697                }
698            }
699            res
700        }
701        Expression::Negate(ref e) => {
702            let res = match solve_expression(e.as_ref(), identifiers, document) {
703                SolverResult::True => SolverResult::False,
704                SolverResult::False => SolverResult::True,
705                SolverResult::Missing => SolverResult::False,
706            };
707            debug!("evaluating {} for {}", res, expression);
708            res
709        }
710        Expression::Nested(ref s, ref e) => {
711            let value = match document.find(s) {
712                Some(v) => v,
713                None => {
714                    debug!("evaluating missing, field not found for {}", expression);
715                    return SolverResult::Missing;
716                }
717            };
718            match value {
719                Value::Object(o) => solve_expression(e, identifiers, &o),
720                Value::Array(a) => {
721                    if let Expression::Match(Match::All, expression) = &**e {
722                        if let Expression::BooleanGroup(BoolSym::Or, expressions) = &**expression {
723                            for expression in expressions {
724                                let mut res = SolverResult::Missing;
725                                for v in a.iter() {
726                                    if let Some(x) = v.as_object() {
727                                        match solve_expression(expression, identifiers, &x) {
728                                            SolverResult::True => {
729                                                res = SolverResult::True;
730                                                break;
731                                            }
732                                            SolverResult::False => res = SolverResult::False,
733                                            SolverResult::Missing => {}
734                                        }
735                                    }
736                                }
737                                if res != SolverResult::True {
738                                    return res;
739                                }
740                            }
741                            return SolverResult::True;
742                        } else if let Expression::Matrix(columns, rows) = &**expression {
743                            // NOTE: We can't really make use of the optimisations provided by a
744                            // matrix here as we have to loop through the array! For that reason we
745                            // basically null this optimisation...
746                            for row in rows {
747                                let mut res = SolverResult::Missing;
748                                for v in a.iter() {
749                                    let mut hit = SolverResult::True;
750                                    for (i, expression) in row.iter().enumerate() {
751                                        if let Some(expression) = expression {
752                                            if let Some(x) = v.as_object() {
753                                                let value = x.find(&columns[i]);
754                                                match solve_expression(
755                                                    expression,
756                                                    identifiers,
757                                                    &Passthrough(value),
758                                                ) {
759                                                    SolverResult::True => {}
760                                                    SolverResult::False => {
761                                                        hit = SolverResult::False;
762                                                        break;
763                                                    }
764                                                    SolverResult::Missing => {
765                                                        hit = SolverResult::Missing;
766                                                        break;
767                                                    }
768                                                }
769                                            }
770                                        }
771                                    }
772                                    if hit == SolverResult::True {
773                                        res = SolverResult::True;
774                                        break;
775                                    }
776                                }
777                                if res != SolverResult::True {
778                                    return res;
779                                }
780                            }
781                            return SolverResult::True;
782                        }
783                    }
784                    for v in a.iter() {
785                        if let Some(x) = v.as_object() {
786                            if solve_expression(e, identifiers, &x) == SolverResult::True {
787                                return SolverResult::True;
788                            }
789                        }
790                    }
791                    SolverResult::False
792                }
793                _ => {
794                    debug!(
795                        "evaluating false, field is not an array of objects or object for {}",
796                        expression
797                    );
798                    SolverResult::False
799                }
800            }
801        }
802        Expression::Search(ref s, ref f, ref c) => {
803            let value = match document.find(f) {
804                Some(v) => v,
805                None => {
806                    debug!("evaluating missing, field not found for {}", expression);
807                    return SolverResult::Missing;
808                }
809            };
810            let res = match (value, c) {
811                (Value::String(ref x), _) => search(s, x),
812                (Value::Array(a), _) => {
813                    let mut res = SolverResult::False;
814                    for v in a.iter() {
815                        if let Some(x) = v.as_str() {
816                            if search(s, x) == SolverResult::True {
817                                res = SolverResult::True;
818                                break;
819                            }
820                        } else if *c {
821                            let x = match v {
822                                Value::Bool(x) => x.to_string(),
823                                Value::Float(x) => x.to_string(),
824                                Value::Int(x) => x.to_string(),
825                                Value::UInt(x) => x.to_string(),
826                                _ => continue,
827                            };
828                            if search(s, x.as_str()) == SolverResult::True {
829                                res = SolverResult::True;
830                                break;
831                            }
832                        }
833                    }
834                    res
835                }
836                (Value::Bool(x), true) => {
837                    let x = x.to_string();
838                    search(s, x.as_str())
839                }
840                (Value::Float(x), true) => {
841                    let x = x.to_string();
842                    search(s, x.as_str())
843                }
844                (Value::Int(x), true) => {
845                    let x = x.to_string();
846                    search(s, x.as_str())
847                }
848                (Value::UInt(x), true) => {
849                    let x = x.to_string();
850                    search(s, x.as_str())
851                }
852                _ => {
853                    debug!(
854                        "evaluating false, field is not an array of strings, or a string for {}",
855                        expression
856                    );
857                    return SolverResult::Missing;
858                }
859            };
860            debug!("evaluating {} for {}", res, expression);
861            res
862        }
863        Expression::BooleanGroup(_, _)
864        | Expression::Boolean(_)
865        | Expression::Cast(_, _)
866        | Expression::Field(_)
867        | Expression::Float(_)
868        | Expression::Integer(_)
869        | Expression::Null => unreachable!(),
870    }
871}
872
873#[inline]
874fn match_all(
875    expression: &Expression,
876    identifiers: &HashMap<String, Expression>,
877    document: &dyn Document,
878) -> SolverResult {
879    if let Expression::Search(Search::AhoCorasick(a, m, _), i, c) = expression {
880        let value = match document.find(i) {
881            Some(v) => v,
882            None => {
883                debug!("evaluating missing, field not found for {}", expression);
884                return SolverResult::Missing;
885            }
886        };
887        match (value, c) {
888            (Value::String(ref x), _) => {
889                if slow_aho(a, m, x) != m.len() as u64 {
890                    return SolverResult::False;
891                }
892            }
893            (Value::Array(x), _) => {
894                let mut found = false;
895                for v in x.iter() {
896                    if let Some(x) = v.as_str() {
897                        if slow_aho(a, m, x) == m.len() as u64 {
898                            found = true;
899                            break;
900                        }
901                    } else if *c {
902                        let x = match v {
903                            Value::Bool(x) => x.to_string(),
904                            Value::Float(x) => x.to_string(),
905                            Value::Int(x) => x.to_string(),
906                            Value::UInt(x) => x.to_string(),
907                            _ => continue,
908                        };
909                        if slow_aho(a, m, x.as_str()) == m.len() as u64 {
910                            found = true;
911                            break;
912                        }
913                    }
914                }
915                if !found {
916                    return SolverResult::False;
917                }
918            }
919            (Value::Bool(x), true) => {
920                let x = x.to_string();
921                if slow_aho(a, m, x.as_str()) != m.len() as u64 {
922                    return SolverResult::False;
923                }
924            }
925            (Value::Float(x), true) => {
926                let x = x.to_string();
927                if slow_aho(a, m, x.as_str()) != m.len() as u64 {
928                    return SolverResult::False;
929                }
930            }
931            (Value::Int(x), true) => {
932                let x = x.to_string();
933                if slow_aho(a, m, x.as_str()) != m.len() as u64 {
934                    return SolverResult::False;
935                }
936            }
937            (Value::UInt(x), true) => {
938                let x = x.to_string();
939                if slow_aho(a, m, x.as_str()) != m.len() as u64 {
940                    return SolverResult::False;
941                }
942            }
943            (_, _) => {
944                debug!(
945                    "evaluating false, field is not an array of strings, or a string for {}",
946                    expression
947                );
948                return SolverResult::Missing;
949            }
950        }
951    } else if let Expression::Search(Search::RegexSet(s, _), i, c) = expression {
952        let value = match document.find(i) {
953            Some(v) => v,
954            None => {
955                debug!("evaluating missing, field not found for {}", expression);
956                return SolverResult::Missing;
957            }
958        };
959        match (value, c) {
960            (Value::String(ref x), _) => {
961                let mut hits = 0;
962                for _ in s.matches(x).iter() {
963                    hits += 1;
964                }
965                if hits != s.patterns().len() {
966                    return SolverResult::False;
967                }
968            }
969            (Value::Array(x), _) => {
970                let mut found = false;
971                for v in x.iter() {
972                    if let Some(x) = v.as_str() {
973                        let mut hits = 0;
974                        for _ in s.matches(x).iter() {
975                            hits += 1;
976                        }
977                        if hits == s.patterns().len() {
978                            found = true;
979                            break;
980                        }
981                    } else if *c {
982                        let x = match v {
983                            Value::Bool(x) => x.to_string(),
984                            Value::Float(x) => x.to_string(),
985                            Value::Int(x) => x.to_string(),
986                            Value::UInt(x) => x.to_string(),
987                            _ => continue,
988                        };
989                        let mut hits = 0;
990                        for _ in s.matches(x.as_str()).iter() {
991                            hits += 1;
992                        }
993                        if hits == s.patterns().len() {
994                            found = true;
995                            break;
996                        }
997                    }
998                }
999                if !found {
1000                    return SolverResult::False;
1001                }
1002            }
1003            (Value::Bool(x), true) => {
1004                let x = x.to_string();
1005                let mut hits = 0;
1006                for _ in s.matches(x.as_str()).iter() {
1007                    hits += 1;
1008                }
1009                if hits != s.patterns().len() {
1010                    return SolverResult::False;
1011                }
1012            }
1013            (Value::Float(x), true) => {
1014                let x = x.to_string();
1015                let mut hits = 0;
1016                for _ in s.matches(x.as_str()).iter() {
1017                    hits += 1;
1018                }
1019                if hits != s.patterns().len() {
1020                    return SolverResult::False;
1021                }
1022            }
1023            (Value::Int(x), true) => {
1024                let x = x.to_string();
1025                let mut hits = 0;
1026                for _ in s.matches(x.as_str()).iter() {
1027                    hits += 1;
1028                }
1029                if hits != s.patterns().len() {
1030                    return SolverResult::False;
1031                }
1032            }
1033            (Value::UInt(x), true) => {
1034                let x = x.to_string();
1035                let mut hits = 0;
1036                for _ in s.matches(x.as_str()).iter() {
1037                    hits += 1;
1038                }
1039                if hits != s.patterns().len() {
1040                    return SolverResult::False;
1041                }
1042            }
1043            _ => {
1044                debug!(
1045                    "evaluating false, field is not an array of strings, or a string for {}",
1046                    expression
1047                );
1048                return SolverResult::Missing;
1049            }
1050        }
1051    } else if let Expression::Matrix(columns, rows) = expression {
1052        // NOTE: Field and search widths must be the same or tau will panic, for now this is
1053        // fine as only the optimiser can write this expression, and for those using core it is
1054        // on them to ensure they don't break this. There are ways to lock this down and it
1055        // could be done in the future...
1056        let size = columns.len();
1057        let mut cache: Vec<Option<Value>> = Vec::with_capacity(size);
1058        for _ in 0..size {
1059            cache.push(None);
1060        }
1061        for row in rows {
1062            let mut hit = SolverResult::True;
1063            for (i, expression) in row.iter().enumerate() {
1064                if let Some(expression) = expression {
1065                    if cache[i].is_none() {
1066                        let value = match document.find(&columns[i]) {
1067                            Some(v) => v,
1068                            None => {
1069                                debug!("evaluating missing, field not found for {}", expression);
1070                                hit = SolverResult::Missing;
1071                                break;
1072                            }
1073                        };
1074                        let _ = std::mem::replace(&mut cache[i], Some(value));
1075                    }
1076                    match solve_expression(expression, identifiers, &Cache(&cache)) {
1077                        SolverResult::True => {}
1078                        SolverResult::False => {
1079                            hit = SolverResult::False;
1080                            break;
1081                        }
1082                        SolverResult::Missing => {
1083                            hit = SolverResult::Missing;
1084                            break;
1085                        }
1086                    }
1087                }
1088            }
1089            match hit {
1090                SolverResult::True => {}
1091                SolverResult::False => return SolverResult::False,
1092                SolverResult::Missing => return SolverResult::Missing,
1093            }
1094        }
1095    } else {
1096        return solve_expression(expression, identifiers, document);
1097    }
1098    SolverResult::True
1099}
1100
1101#[inline]
1102fn match_of(
1103    expression: &Expression,
1104    identifiers: &HashMap<String, Expression>,
1105    document: &dyn Document,
1106    count: u64,
1107) -> SolverResult {
1108    if count == 0 {
1109        return match solve_expression(expression, identifiers, document) {
1110            SolverResult::True => SolverResult::False,
1111            SolverResult::False => SolverResult::True,
1112            SolverResult::Missing => return SolverResult::Missing,
1113        };
1114    } else if let Expression::Search(Search::AhoCorasick(a, m, _), i, cast) = expression {
1115        let value = match document.find(i) {
1116            Some(v) => v,
1117            None => {
1118                debug!("evaluating missing, field not found for {}", expression);
1119                return SolverResult::Missing;
1120            }
1121        };
1122        match (value, cast) {
1123            (Value::String(ref x), _) => {
1124                let c = slow_aho(a, m, x);
1125                if c >= count {
1126                    return SolverResult::True;
1127                }
1128            }
1129            (Value::Array(x), _) => {
1130                for v in x.iter() {
1131                    if let Some(x) = v.as_str() {
1132                        let hits = slow_aho(a, m, x);
1133                        if hits >= count {
1134                            return SolverResult::True;
1135                        }
1136                    } else if *cast {
1137                        let x = match v {
1138                            Value::Bool(x) => x.to_string(),
1139                            Value::Float(x) => x.to_string(),
1140                            Value::Int(x) => x.to_string(),
1141                            Value::UInt(x) => x.to_string(),
1142                            _ => continue,
1143                        };
1144                        let hits = slow_aho(a, m, x.as_str());
1145                        if hits >= count {
1146                            return SolverResult::True;
1147                        }
1148                    }
1149                }
1150            }
1151            (Value::Bool(x), true) => {
1152                let x = x.to_string();
1153                let c = slow_aho(a, m, x.as_str());
1154                if c >= count {
1155                    return SolverResult::True;
1156                }
1157            }
1158            (Value::Float(x), true) => {
1159                let x = x.to_string();
1160                let c = slow_aho(a, m, x.as_str());
1161                if c >= count {
1162                    return SolverResult::True;
1163                }
1164            }
1165            (Value::Int(x), true) => {
1166                let x = x.to_string();
1167                let c = slow_aho(a, m, x.as_str());
1168                if c >= count {
1169                    return SolverResult::True;
1170                }
1171            }
1172            (Value::UInt(x), true) => {
1173                let x = x.to_string();
1174                let c = slow_aho(a, m, x.as_str());
1175                if c >= count {
1176                    return SolverResult::True;
1177                }
1178            }
1179            _ => {
1180                debug!(
1181                    "evaluating false, field is not an array of strings, or a string for {}",
1182                    expression
1183                );
1184                return SolverResult::Missing;
1185            }
1186        }
1187    } else if let Expression::Search(Search::RegexSet(s, _), i, cast) = expression {
1188        let value = match document.find(i) {
1189            Some(v) => v,
1190            None => {
1191                debug!("evaluating missing, field not found for {}", expression);
1192                return SolverResult::Missing;
1193            }
1194        };
1195        match (value, cast) {
1196            (Value::String(ref x), _) => {
1197                let mut c = 0;
1198                for _ in s.matches(x).iter() {
1199                    c += 1;
1200                }
1201                if c >= count {
1202                    return SolverResult::True;
1203                }
1204            }
1205            (Value::Array(x), _) => {
1206                for v in x.iter() {
1207                    if let Some(x) = v.as_str() {
1208                        let mut hits = 0;
1209                        for _ in s.matches(x).iter() {
1210                            hits += 1;
1211                        }
1212                        if hits >= count {
1213                            return SolverResult::True;
1214                        }
1215                    } else if *cast {
1216                        let x = match v {
1217                            Value::Bool(x) => x.to_string(),
1218                            Value::Float(x) => x.to_string(),
1219                            Value::Int(x) => x.to_string(),
1220                            Value::UInt(x) => x.to_string(),
1221                            _ => continue,
1222                        };
1223                        let mut hits = 0;
1224                        for _ in s.matches(x.as_str()).iter() {
1225                            hits += 1;
1226                        }
1227                        if hits >= count {
1228                            return SolverResult::True;
1229                        }
1230                    }
1231                }
1232            }
1233            (Value::Bool(x), true) => {
1234                let x = x.to_string();
1235                let mut c = 0;
1236                for _ in s.matches(x.as_str()).iter() {
1237                    c += 1;
1238                }
1239                if c >= count {
1240                    return SolverResult::True;
1241                }
1242            }
1243            (Value::Float(x), true) => {
1244                let x = x.to_string();
1245                let mut c = 0;
1246                for _ in s.matches(x.as_str()).iter() {
1247                    c += 1;
1248                }
1249                if c >= count {
1250                    return SolverResult::True;
1251                }
1252            }
1253            (Value::Int(x), true) => {
1254                let x = x.to_string();
1255                let mut c = 0;
1256                for _ in s.matches(x.as_str()).iter() {
1257                    c += 1;
1258                }
1259                if c >= count {
1260                    return SolverResult::True;
1261                }
1262            }
1263            (Value::UInt(x), true) => {
1264                let x = x.to_string();
1265                let mut c = 0;
1266                for _ in s.matches(x.as_str()).iter() {
1267                    c += 1;
1268                }
1269                if c >= count {
1270                    return SolverResult::True;
1271                }
1272            }
1273            _ => {
1274                debug!(
1275                    "evaluating false, field is not an array of strings, or a string for {}",
1276                    expression
1277                );
1278                return SolverResult::Missing;
1279            }
1280        }
1281    } else if let Expression::Matrix(columns, rows) = expression {
1282        // NOTE: Field and search widths must be the same or tau will panic, for now this is
1283        // fine as only the optimiser can write this expression, and for those using core it is
1284        // on them to ensure they don't break this. There are ways to lock this down and it
1285        // could be done in the future...
1286        let size = columns.len();
1287        let mut cache: Vec<Option<Value>> = Vec::with_capacity(size);
1288        for _ in 0..size {
1289            cache.push(None);
1290        }
1291        let mut hits = 0;
1292        let mut res = SolverResult::Missing;
1293        for row in rows {
1294            let mut hit = SolverResult::True;
1295            for (i, expression) in row.iter().enumerate() {
1296                if let Some(expression) = expression {
1297                    if cache[i].is_none() {
1298                        let value = match document.find(&columns[i]) {
1299                            Some(v) => v,
1300                            None => {
1301                                debug!("evaluating missing, field not found for {}", expression);
1302                                hit = SolverResult::Missing;
1303                                break;
1304                            }
1305                        };
1306                        let _ = std::mem::replace(&mut cache[i], Some(value));
1307                    }
1308                    match solve_expression(expression, identifiers, &Cache(&cache)) {
1309                        SolverResult::True => {}
1310                        SolverResult::False => {
1311                            hit = SolverResult::False;
1312                            break;
1313                        }
1314                        SolverResult::Missing => {
1315                            hit = SolverResult::Missing;
1316                            break;
1317                        }
1318                    }
1319                }
1320            }
1321            match hit {
1322                SolverResult::True => {
1323                    hits += 1;
1324                    if hits >= count {
1325                        return SolverResult::True;
1326                    }
1327                }
1328                SolverResult::False => res = SolverResult::False,
1329                SolverResult::Missing => {}
1330            }
1331        }
1332        return res;
1333    } else {
1334        return solve_expression(expression, identifiers, document);
1335    }
1336    SolverResult::False
1337}
1338
1339#[inline]
1340fn search(kind: &Search, value: &str) -> SolverResult {
1341    match kind {
1342        Search::Any => {
1343            return SolverResult::True;
1344        }
1345        Search::Exact(i) => {
1346            if i == value {
1347                return SolverResult::True;
1348            }
1349        }
1350        Search::Contains(i) => {
1351            if value.contains(i) {
1352                return SolverResult::True;
1353            }
1354        }
1355        Search::EndsWith(i) => {
1356            if value.ends_with(i) {
1357                return SolverResult::True;
1358            }
1359        }
1360        Search::StartsWith(i) => {
1361            if value.starts_with(i) {
1362                return SolverResult::True;
1363            }
1364        }
1365        Search::Regex(i, _) => {
1366            if i.is_match(value) {
1367                return SolverResult::True;
1368            }
1369        }
1370        Search::RegexSet(i, _) => {
1371            if i.is_match(value) {
1372                return SolverResult::True;
1373            }
1374        }
1375        Search::AhoCorasick(a, m, _) => {
1376            for i in a.find_overlapping_iter(value) {
1377                match m[i.pattern()] {
1378                    MatchType::Contains(_) => return SolverResult::True,
1379                    MatchType::EndsWith(_) => {
1380                        if i.end() == value.len() {
1381                            return SolverResult::True;
1382                        }
1383                    }
1384                    MatchType::Exact(_) => {
1385                        if i.start() == 0 && i.end() == value.len() {
1386                            return SolverResult::True;
1387                        }
1388                    }
1389                    MatchType::StartsWith(_) => {
1390                        if i.start() == 0 {
1391                            return SolverResult::True;
1392                        }
1393                    }
1394                }
1395            }
1396            return SolverResult::False;
1397        }
1398    }
1399    SolverResult::False
1400}
1401
1402#[inline]
1403fn slow_aho(a: &AhoCorasick, m: &[MatchType], value: &str) -> u64 {
1404    // TODO: Benchmark properly to work out whether the bitmap really is better on average
1405    let len = m.len();
1406    if len < 64 {
1407        let mut map = 0;
1408        for i in a.find_overlapping_iter(value) {
1409            let p = i.pattern();
1410            match m[p] {
1411                MatchType::Contains(_) => {
1412                    map |= 1 << p.as_u64();
1413                }
1414                MatchType::EndsWith(_) => {
1415                    if i.end() == value.len() {
1416                        map |= 1 << p.as_u64();
1417                    }
1418                }
1419                MatchType::Exact(_) => {
1420                    if i.start() == 0 && i.end() == value.len() {
1421                        map |= 1 << p.as_u64();
1422                    }
1423                }
1424                MatchType::StartsWith(_) => {
1425                    if i.start() == 0 {
1426                        map |= 1 << p.as_u64();
1427                    }
1428                }
1429            }
1430        }
1431        let mut hits = 0;
1432        for i in 0..len {
1433            hits += (map >> i) & 0x1;
1434        }
1435        hits
1436    } else {
1437        let mut hits = std::collections::HashSet::with_capacity(len);
1438        for i in a.find_overlapping_iter(value) {
1439            let p = i.pattern();
1440            match m[p] {
1441                MatchType::Contains(_) => {
1442                    hits.insert(p);
1443                }
1444                MatchType::EndsWith(_) => {
1445                    if i.end() == value.len() {
1446                        hits.insert(p);
1447                    }
1448                }
1449                MatchType::Exact(_) => {
1450                    if i.start() == 0 && i.end() == value.len() {
1451                        hits.insert(p);
1452                    }
1453                }
1454                MatchType::StartsWith(_) => {
1455                    if i.start() == 0 {
1456                        hits.insert(p);
1457                    }
1458                }
1459            }
1460        }
1461        hits.len() as u64
1462    }
1463}