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