dysk_cli/
filter.rs

1use {
2    crate::{
3        col_expr::*,
4    },
5    bet::*,
6    lfs_core::*,
7    std::{
8        str::FromStr,
9    },
10};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13enum BoolOperator {
14    And,
15    Or,
16    Not,
17}
18
19#[derive(Debug, Default, Clone)]
20pub struct Filter {
21    expr: BeTree<BoolOperator, ColExpr>,
22}
23
24impl Filter {
25    #[allow(clippy::match_like_matches_macro)]
26    pub fn eval(&self, mount: &Mount) -> Result<bool, EvalExprError> {
27        self.expr.eval_faillible(
28            // leaf evaluation
29            |col_expr| col_expr.eval(mount),
30            // bool operation
31            |op, a, b| match (op, b) {
32                (BoolOperator::And, Some(b)) => Ok(a & b),
33                (BoolOperator::Or, Some(b)) => Ok(a | b),
34                (BoolOperator::Not, None) => Ok(!a),
35                _ => { unreachable!() }
36            },
37            // when to short-circuit
38            |op, a| match (op, a) {
39                (BoolOperator::And, false) => true,
40                (BoolOperator::Or, true) => true,
41                _ => false,
42            },
43        ).map(|b| b.unwrap_or(true))
44    }
45    pub fn filter<'m>(&self, mounts: &'m[Mount]) -> Result<Vec<&'m Mount>, EvalExprError> {
46        let mut filtered = Vec::new();
47        for mount in mounts {
48            if self.eval(mount)? {
49                filtered.push(mount);
50            }
51        }
52        Ok(filtered)
53    }
54}
55
56impl FromStr for Filter {
57    type Err = ParseExprError;
58    fn from_str(input: &str) -> Result<Self, ParseExprError> {
59
60        // we start by reading the global structure
61        let mut expr: BeTree<BoolOperator, String> = BeTree::new();
62        for c in input.chars() {
63            match c {
64                '&' => expr.push_operator(BoolOperator::And),
65                '|' => expr.push_operator(BoolOperator::Or),
66                '!' => expr.push_operator(BoolOperator::Not),
67                ' ' => {},
68                '(' => expr.open_par(),
69                ')' => expr.close_par(),
70                _ => expr.mutate_or_create_atom(String::new).push(c),
71            }
72        }
73
74        // then we parse each leaf
75        let expr = expr.try_map_atoms(|raw| raw.parse())?;
76
77        Ok(Self { expr })
78    }
79}
80
81