automapper_validation/expr/
ast.rs1use std::collections::BTreeSet;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
19pub enum ConditionExpr {
20 Ref(u32),
22
23 And(Vec<ConditionExpr>),
26
27 Or(Vec<ConditionExpr>),
30
31 Xor(Box<ConditionExpr>, Box<ConditionExpr>),
33
34 Not(Box<ConditionExpr>),
36
37 Package { id: u32, min: u32, max: u32 },
39}
40
41impl ConditionExpr {
42 pub fn condition_ids(&self) -> BTreeSet<u32> {
44 let mut ids = BTreeSet::new();
45 self.collect_ids(&mut ids);
46 ids
47 }
48
49 fn collect_ids(&self, ids: &mut BTreeSet<u32>) {
50 match self {
51 ConditionExpr::Ref(id) => {
52 ids.insert(*id);
53 }
54 ConditionExpr::And(exprs) | ConditionExpr::Or(exprs) => {
55 for expr in exprs {
56 expr.collect_ids(ids);
57 }
58 }
59 ConditionExpr::Xor(left, right) => {
60 left.collect_ids(ids);
61 right.collect_ids(ids);
62 }
63 ConditionExpr::Not(inner) => {
64 inner.collect_ids(ids);
65 }
66 ConditionExpr::Package { .. } => {
67 }
69 }
70 }
71}
72
73impl std::fmt::Display for ConditionExpr {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 match self {
76 ConditionExpr::Ref(id) => write!(f, "[{id}]"),
77 ConditionExpr::And(exprs) => {
78 let parts: Vec<String> = exprs.iter().map(|e| format!("{e}")).collect();
79 write!(f, "({})", parts.join(" ∧ "))
80 }
81 ConditionExpr::Or(exprs) => {
82 let parts: Vec<String> = exprs.iter().map(|e| format!("{e}")).collect();
83 write!(f, "({})", parts.join(" ∨ "))
84 }
85 ConditionExpr::Xor(left, right) => write!(f, "({left} ⊻ {right})"),
86 ConditionExpr::Not(inner) => write!(f, "NOT {inner}"),
87 ConditionExpr::Package { id, min, max } => write!(f, "[{id}P{min}..{max}]"),
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn test_ref_condition_ids() {
98 let expr = ConditionExpr::Ref(931);
99 assert_eq!(expr.condition_ids(), [931].into());
100 }
101
102 #[test]
103 fn test_and_condition_ids() {
104 let expr = ConditionExpr::And(vec![
105 ConditionExpr::Ref(1),
106 ConditionExpr::Ref(2),
107 ConditionExpr::Ref(3),
108 ]);
109 assert_eq!(expr.condition_ids(), [1, 2, 3].into());
110 }
111
112 #[test]
113 fn test_nested_condition_ids() {
114 let expr = ConditionExpr::Xor(
116 Box::new(ConditionExpr::Or(vec![
117 ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]),
118 ConditionExpr::And(vec![ConditionExpr::Ref(3), ConditionExpr::Ref(4)]),
119 ])),
120 Box::new(ConditionExpr::Ref(5)),
121 );
122 assert_eq!(expr.condition_ids(), [1, 2, 3, 4, 5].into());
123 }
124
125 #[test]
126 fn test_not_condition_ids() {
127 let expr = ConditionExpr::Not(Box::new(ConditionExpr::Ref(42)));
128 assert_eq!(expr.condition_ids(), [42].into());
129 }
130
131 #[test]
132 fn test_display_ref() {
133 let expr = ConditionExpr::Ref(931);
134 assert_eq!(format!("{expr}"), "[931]");
135 }
136
137 #[test]
138 fn test_display_and() {
139 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
140 assert_eq!(format!("{expr}"), "([1] ∧ [2])");
141 }
142
143 #[test]
144 fn test_display_complex() {
145 let expr = ConditionExpr::Xor(
146 Box::new(ConditionExpr::And(vec![
147 ConditionExpr::Ref(102),
148 ConditionExpr::Ref(2006),
149 ])),
150 Box::new(ConditionExpr::And(vec![
151 ConditionExpr::Ref(103),
152 ConditionExpr::Ref(2005),
153 ])),
154 );
155 assert_eq!(format!("{expr}"), "(([102] ∧ [2006]) ⊻ ([103] ∧ [2005]))");
156 }
157
158 #[test]
159 fn test_display_not() {
160 let expr = ConditionExpr::Not(Box::new(ConditionExpr::Ref(1)));
161 assert_eq!(format!("{expr}"), "NOT [1]");
162 }
163
164 #[test]
165 fn test_equality() {
166 let a = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
167 let b = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
168 assert_eq!(a, b);
169 }
170
171 #[test]
172 fn test_inequality() {
173 let a = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
174 let b = ConditionExpr::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
175 assert_ne!(a, b);
176 }
177
178 #[test]
179 fn test_package_condition_ids() {
180 let expr = ConditionExpr::Package {
181 id: 4,
182 min: 0,
183 max: 1,
184 };
185 assert!(
186 expr.condition_ids().is_empty(),
187 "Package nodes have no condition IDs"
188 );
189 }
190
191 #[test]
192 fn test_package_display() {
193 let expr = ConditionExpr::Package {
194 id: 4,
195 min: 0,
196 max: 1,
197 };
198 assert_eq!(format!("{expr}"), "[4P0..1]");
199 }
200
201 #[test]
202 fn test_clone() {
203 let expr = ConditionExpr::Xor(
204 Box::new(ConditionExpr::Ref(1)),
205 Box::new(ConditionExpr::Ref(2)),
206 );
207 let cloned = expr.clone();
208 assert_eq!(expr, cloned);
209 }
210}