Skip to main content

manabrew_engine/parsing/
compare.rs

1//! Comparison utilities for Forge DSL expressions.
2//!
3//! Mirrors Java's `Expressions.compare()` — parses comparator strings like
4//! `"GE2"`, `"LT5"`, `"EQ0"` and evaluates them against integer values.
5//!
6//! Used by `IsPresent$/PresentCompare$`, `CheckSVar$/SVarCompare$`,
7//! `ConditionCompare$`, and similar parameter patterns.
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum CompareOp {
11    GreaterOrEqual,
12    GreaterThan,
13    LessOrEqual,
14    LessThan,
15    Equal,
16    NotEqual,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct CompareExpr {
21    pub op: CompareOp,
22    pub threshold: i32,
23}
24
25impl CompareExpr {
26    pub fn parse(expr: &str) -> Option<Self> {
27        let (op, rest) = if let Some(rest) = expr.strip_prefix("GE") {
28            (CompareOp::GreaterOrEqual, rest)
29        } else if let Some(rest) = expr.strip_prefix("GT") {
30            (CompareOp::GreaterThan, rest)
31        } else if let Some(rest) = expr.strip_prefix("LE") {
32            (CompareOp::LessOrEqual, rest)
33        } else if let Some(rest) = expr.strip_prefix("LT") {
34            (CompareOp::LessThan, rest)
35        } else if let Some(rest) = expr.strip_prefix("NE") {
36            (CompareOp::NotEqual, rest)
37        } else if let Some(rest) = expr.strip_prefix("EQ") {
38            (CompareOp::Equal, rest)
39        } else {
40            return None;
41        };
42        Some(Self {
43            op,
44            threshold: rest.parse::<i32>().ok()?,
45        })
46    }
47
48    pub fn evaluate(self, value: i32) -> bool {
49        match self.op {
50            CompareOp::GreaterOrEqual => value >= self.threshold,
51            CompareOp::GreaterThan => value > self.threshold,
52            CompareOp::LessOrEqual => value <= self.threshold,
53            CompareOp::LessThan => value < self.threshold,
54            CompareOp::Equal => value == self.threshold,
55            CompareOp::NotEqual => value != self.threshold,
56        }
57    }
58}
59
60/// Compare a value against a DSL comparator expression.
61///
62/// The expression is a prefix (`GE`, `GT`, `LE`, `LT`, `EQ`, `NE`) followed
63/// by an integer threshold. For example, `"GE2"` means "greater than or equal
64/// to 2".
65///
66/// Returns `true` if the comparison matches, or `true` on unknown format
67/// (permissive fallback, matching Java behavior).
68///
69/// # Examples
70///
71/// ```
72/// use manabrew_engine::parsing::compare::compare_expr;
73///
74/// assert!(compare_expr(3, "GE2"));
75/// assert!(compare_expr(2, "GE2"));
76/// assert!(!compare_expr(1, "GE2"));
77/// assert!(compare_expr(0, "EQ0"));
78/// assert!(!compare_expr(1, "EQ0"));
79/// assert!(compare_expr(5, "GT4"));
80/// assert!(!compare_expr(4, "GT4"));
81/// ```
82pub fn compare_expr(value: i32, expr: &str) -> bool {
83    if let Some(parsed) = CompareExpr::parse(expr) {
84        parsed.evaluate(value)
85    } else {
86        // Unknown comparator — permissive fallback (matches Java).
87        true
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn ge() {
97        assert!(compare_expr(2, "GE2"));
98        assert!(compare_expr(3, "GE2"));
99        assert!(!compare_expr(1, "GE2"));
100    }
101
102    #[test]
103    fn gt() {
104        assert!(compare_expr(3, "GT2"));
105        assert!(!compare_expr(2, "GT2"));
106    }
107
108    #[test]
109    fn le() {
110        assert!(compare_expr(2, "LE2"));
111        assert!(compare_expr(1, "LE2"));
112        assert!(!compare_expr(3, "LE2"));
113    }
114
115    #[test]
116    fn lt() {
117        assert!(compare_expr(1, "LT2"));
118        assert!(!compare_expr(2, "LT2"));
119    }
120
121    #[test]
122    fn eq() {
123        assert!(compare_expr(0, "EQ0"));
124        assert!(!compare_expr(1, "EQ0"));
125    }
126
127    #[test]
128    fn ne() {
129        assert!(compare_expr(1, "NE0"));
130        assert!(!compare_expr(0, "NE0"));
131    }
132
133    #[test]
134    fn unknown_is_permissive() {
135        assert!(compare_expr(42, "UNKNOWN"));
136        assert!(compare_expr(0, ""));
137    }
138}