1use super::{Condition, Expression, ExpressionError};
2use asexp::Sexp;
3use std::fmt::Debug;
4
5#[derive(Debug, Clone, PartialEq)]
7pub enum Cond<E: Expression> {
8 True,
9 False,
10 Not(Box<Cond<E>>),
11 And(Box<Cond<E>>, Box<Cond<E>>),
12 Or(Box<Cond<E>>, Box<Cond<E>>),
13
14 Equal(Box<E>, Box<E>),
16
17 Less(Box<E>, Box<E>),
18 Greater(Box<E>, Box<E>),
19
20 LessEqual(Box<E>, Box<E>),
21 GreaterEqual(Box<E>, Box<E>),
22}
23
24impl<E: Expression> Condition for Cond<E> {
25 type Expr = E;
26 fn evaluate(
27 &self,
28 variables: &[<Self::Expr as Expression>::Element],
29 ) -> Result<bool, ExpressionError> {
30 Ok(match *self {
31 Cond::True => true,
32 Cond::False => false,
33 Cond::Not(ref c) => !c.evaluate(variables)?,
34 Cond::And(ref c1, ref c2) => c1.evaluate(variables)? && c2.evaluate(variables)?,
35 Cond::Or(ref c1, ref c2) => c1.evaluate(variables)? || c2.evaluate(variables)?,
36 Cond::Equal(ref e1, ref e2) => e1.evaluate(variables)? == e2.evaluate(variables)?,
37 Cond::Less(ref e1, ref e2) => e1.evaluate(variables)? < e2.evaluate(variables)?,
38 Cond::Greater(ref e1, ref e2) => e1.evaluate(variables)? > e2.evaluate(variables)?,
39 Cond::LessEqual(ref e1, ref e2) => e1.evaluate(variables)? <= e2.evaluate(variables)?,
40 Cond::GreaterEqual(ref e1, ref e2) => {
41 e1.evaluate(variables)? >= e2.evaluate(variables)?
42 }
43 })
44 }
45}
46
47impl<'a, E, T> Into<Sexp> for &'a Cond<E>
48where
49 E: Expression<Element = T>,
50 &'a E: Into<Sexp>,
51 T: Debug + Copy + Clone + PartialEq + PartialOrd,
52{
53 fn into(self) -> Sexp {
54 match self {
55 &Cond::True => Sexp::from("true"),
56 &Cond::False => Sexp::from("false"),
57 &Cond::Not(ref a) => Sexp::from(("not", Into::<Sexp>::into(a.as_ref()))),
58 &Cond::And(ref a, ref b) => Sexp::from((
59 "and",
60 Into::<Sexp>::into(a.as_ref()),
61 Into::<Sexp>::into(b.as_ref()),
62 )),
63 &Cond::Or(ref a, ref b) => Sexp::from((
64 "or",
65 Into::<Sexp>::into(a.as_ref()),
66 Into::<Sexp>::into(b.as_ref()),
67 )),
68 &Cond::Equal(ref a, ref b) => Sexp::from((
69 "==",
70 Into::<Sexp>::into(a.as_ref()),
71 Into::<Sexp>::into(b.as_ref()),
72 )),
73 &Cond::Less(ref a, ref b) => Sexp::from((
74 "<",
75 Into::<Sexp>::into(a.as_ref()),
76 Into::<Sexp>::into(b.as_ref()),
77 )),
78 &Cond::Greater(ref a, ref b) => Sexp::from((
79 ">",
80 Into::<Sexp>::into(a.as_ref()),
81 Into::<Sexp>::into(b.as_ref()),
82 )),
83 &Cond::LessEqual(ref a, ref b) => Sexp::from((
84 "<=",
85 Into::<Sexp>::into(a.as_ref()),
86 Into::<Sexp>::into(b.as_ref()),
87 )),
88 &Cond::GreaterEqual(ref a, ref b) => Sexp::from((
89 ">=",
90 Into::<Sexp>::into(a.as_ref()),
91 Into::<Sexp>::into(b.as_ref()),
92 )),
93 }
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use crate::{cond::Cond, Condition, Expression, ExpressionError};
100
101 #[derive(Debug, Clone, PartialEq, PartialOrd)]
102 struct ConstNum(f32);
103
104 impl Expression for ConstNum {
105 type Element = f32;
106 fn evaluate(&self, _variables: &[Self::Element]) -> Result<Self::Element, ExpressionError> {
107 Ok(self.0)
108 }
109 }
110
111 #[test]
112 fn test_condition() {
113 let no_vars: &[f32] = &[];
114
115 let cond = Cond::Greater(Box::new(ConstNum(0.1)), Box::new(ConstNum(0.2)));
116 assert_eq!(Ok(false), cond.evaluate(no_vars));
117
118 let cond = Cond::Not(Box::new(Cond::Greater(
119 Box::new(ConstNum(0.1)),
120 Box::new(ConstNum(0.2)),
121 )));
122 assert_eq!(Ok(true), cond.evaluate(no_vars));
123 }
124}