bool_logic/transforms/
dedup_list.rs

1use crate::ast::Expr;
2use crate::visit_mut::VisitMut;
3use crate::visit_mut::walk_mut_expr;
4
5pub struct DedupList;
6
7impl<T> VisitMut<T> for DedupList
8where
9    T: Eq,
10{
11    fn visit_mut_expr(&mut self, expr: &mut Expr<T>) {
12        walk_mut_expr(self, expr);
13
14        if let Some(list) = expr.as_mut_expr_list() {
15            let mut i = 0;
16            while i < list.len() {
17                let mut j = i + 1;
18                while j < list.len() {
19                    if list[i] == list[j] {
20                        list.remove(j);
21                    } else {
22                        j += 1;
23                    }
24                }
25                i += 1;
26            }
27        }
28    }
29}
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34    use crate::ast::{all, any, const_, expr, not, var};
35
36    #[test]
37    fn dedup_any_with_duplicates() {
38        let mut x: Expr<u32> = expr(any((var(1), var(2), var(1), var(3), var(2))));
39        let expected: Expr<u32> = expr(any((var(1), var(2), var(3))));
40
41        DedupList.visit_mut_expr(&mut x);
42
43        assert_eq!(x.to_string(), expected.to_string());
44    }
45
46    #[test]
47    fn dedup_all_with_duplicates() {
48        let mut x: Expr<u32> = expr(all((var(1), var(2), var(1), var(3), var(2))));
49        let expected: Expr<u32> = expr(all((var(1), var(2), var(3))));
50
51        DedupList.visit_mut_expr(&mut x);
52
53        assert_eq!(x.to_string(), expected.to_string());
54    }
55
56    #[test]
57    fn dedup_no_duplicates() {
58        let mut x: Expr<u32> = expr(any((var(1), var(2), var(3))));
59        let expected: Expr<u32> = expr(any((var(1), var(2), var(3))));
60
61        DedupList.visit_mut_expr(&mut x);
62
63        assert_eq!(x.to_string(), expected.to_string());
64    }
65
66    #[test]
67    fn dedup_empty_list() {
68        let mut x: Expr<u32> = expr(any(()));
69        let expected: Expr<u32> = expr(any(()));
70
71        DedupList.visit_mut_expr(&mut x);
72
73        assert_eq!(x.to_string(), expected.to_string());
74    }
75
76    #[test]
77    fn dedup_single_element() {
78        let mut x: Expr<u32> = expr(any((var(1),)));
79        let expected: Expr<u32> = expr(any((var(1),)));
80
81        DedupList.visit_mut_expr(&mut x);
82
83        assert_eq!(x.to_string(), expected.to_string());
84    }
85
86    #[test]
87    fn dedup_all_same_elements() {
88        let mut x: Expr<u32> = expr(any((var(1), var(1), var(1), var(1))));
89        let expected: Expr<u32> = expr(any((var(1),)));
90
91        DedupList.visit_mut_expr(&mut x);
92
93        assert_eq!(x.to_string(), expected.to_string());
94    }
95
96    #[test]
97    fn dedup_nested_expressions() {
98        let mut x: Expr<u32> = expr(any((
99            all((var(1), var(2))),
100            var(3),
101            all((var(1), var(2))),
102            var(3),
103        )));
104        let expected: Expr<u32> = expr(any((all((var(1), var(2))), var(3))));
105
106        DedupList.visit_mut_expr(&mut x);
107
108        assert_eq!(x.to_string(), expected.to_string());
109    }
110
111    #[test]
112    fn dedup_with_constants() {
113        let mut x: Expr<u32> = expr(any((const_(true), var(1), const_(true), const_(false))));
114        let expected: Expr<u32> = expr(any((const_(true), var(1), const_(false))));
115
116        DedupList.visit_mut_expr(&mut x);
117
118        assert_eq!(x.to_string(), expected.to_string());
119    }
120
121    #[test]
122    fn dedup_preserves_order() {
123        let mut x: Expr<u32> = expr(any((var(3), var(1), var(2), var(1), var(3))));
124        let expected: Expr<u32> = expr(any((var(3), var(1), var(2))));
125
126        DedupList.visit_mut_expr(&mut x);
127
128        assert_eq!(x.to_string(), expected.to_string());
129    }
130
131    #[test]
132    fn dedup_non_list_expression() {
133        let mut x: Expr<u32> = expr(not(var(1)));
134        let expected: Expr<u32> = expr(not(var(1)));
135
136        DedupList.visit_mut_expr(&mut x);
137
138        assert_eq!(x.to_string(), expected.to_string());
139    }
140}