toasty_core/stmt/
expr_or.rs

1use super::Expr;
2use std::ops;
3
4/// A logical "or" of multiple expressions.
5///
6/// Returns `true` if at least one operand evaluates to `true`. An `ExprOr`
7/// always has at least two operands; use [`Expr::or_from_vec`] which returns
8/// `Expr::Value(false)` for empty input and unwraps single-element input.
9///
10/// # Examples
11///
12/// ```text
13/// or(a, b, c)  // returns `true` if any of `a`, `b`, or `c` is `true`
14/// ```
15#[derive(Debug, Clone, PartialEq)]
16pub struct ExprOr {
17    /// The expressions to "or" together.
18    pub operands: Vec<Expr>,
19}
20
21impl Expr {
22    pub fn or(lhs: impl Into<Self>, rhs: impl Into<Self>) -> Self {
23        let mut lhs = lhs.into();
24        let rhs = rhs.into();
25
26        match (&mut lhs, rhs) {
27            (Self::Or(lhs_or), Self::Or(rhs_or)) => {
28                lhs_or.operands.extend(rhs_or.operands);
29                lhs
30            }
31            (Self::Or(lhs_or), rhs) => {
32                lhs_or.operands.push(rhs);
33                lhs
34            }
35            (_, Self::Or(mut lhs_or)) => {
36                lhs_or.operands.push(lhs);
37                lhs_or.into()
38            }
39            (_, rhs) => ExprOr {
40                operands: vec![lhs, rhs],
41            }
42            .into(),
43        }
44    }
45
46    pub fn or_from_vec(operands: Vec<Self>) -> Self {
47        if operands.is_empty() {
48            return false.into();
49        }
50
51        if operands.len() == 1 {
52            return operands.into_iter().next().unwrap();
53        }
54
55        ExprOr { operands }.into()
56    }
57}
58
59impl ops::Deref for ExprOr {
60    type Target = [Expr];
61
62    fn deref(&self) -> &Self::Target {
63        self.operands.deref()
64    }
65}
66
67impl<'a> IntoIterator for &'a ExprOr {
68    type IntoIter = std::slice::Iter<'a, Expr>;
69    type Item = &'a Expr;
70
71    fn into_iter(self) -> Self::IntoIter {
72        self.operands.iter()
73    }
74}
75
76impl<'a> IntoIterator for &'a mut ExprOr {
77    type IntoIter = std::slice::IterMut<'a, Expr>;
78    type Item = &'a mut Expr;
79
80    fn into_iter(self) -> Self::IntoIter {
81        self.operands.iter_mut()
82    }
83}
84
85impl From<ExprOr> for Expr {
86    fn from(value: ExprOr) -> Self {
87        Self::Or(value)
88    }
89}