vortex_mask/
eq.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use crate::Mask;
5
6impl PartialEq for Mask {
7    fn eq(&self, other: &Self) -> bool {
8        if self.len() != other.len() {
9            return false;
10        }
11        if self.true_count() != other.true_count() {
12            return false;
13        }
14
15        // TODO(ngates): we could compare by indices if density is low enough
16        self.boolean_buffer() == other.boolean_buffer()
17    }
18}
19
20impl Eq for Mask {}
21
22#[cfg(test)]
23mod test {
24    use arrow_buffer::BooleanBuffer;
25
26    use crate::Mask;
27
28    #[test]
29    fn filter_mask_eq() {
30        assert_eq!(
31            Mask::new_true(5),
32            Mask::from_buffer(BooleanBuffer::new_set(5))
33        );
34        assert_eq!(
35            Mask::new_false(5),
36            Mask::from_buffer(BooleanBuffer::new_unset(5))
37        );
38        assert_eq!(
39            Mask::from_indices(5, vec![0, 2, 3]),
40            Mask::from_slices(5, vec![(0, 1), (2, 4)])
41        );
42        assert_eq!(
43            Mask::from_indices(5, vec![0, 2, 3]),
44            Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, true, false]))
45        );
46    }
47
48    #[test]
49    fn test_mask_eq_different_lengths() {
50        let mask1 = Mask::new_true(5);
51        let mask2 = Mask::new_true(3);
52        assert_ne!(mask1, mask2);
53    }
54
55    #[test]
56    fn test_mask_eq_different_true_counts() {
57        let mask1 = Mask::from_buffer(BooleanBuffer::from_iter([true, true, false]));
58        let mask2 = Mask::from_buffer(BooleanBuffer::from_iter([true, false, false]));
59        assert_ne!(mask1, mask2);
60    }
61
62    #[test]
63    fn test_mask_eq_same_count_different_positions() {
64        let mask1 = Mask::from_buffer(BooleanBuffer::from_iter([true, false, false]));
65        let mask2 = Mask::from_buffer(BooleanBuffer::from_iter([false, true, false]));
66        assert_ne!(mask1, mask2);
67    }
68
69    #[test]
70    fn test_mask_eq_all_variants() {
71        // Test AllTrue == AllTrue
72        let all_true1 = Mask::new_true(5);
73        let all_true2 = Mask::new_true(5);
74        assert_eq!(all_true1, all_true2);
75
76        // Test AllFalse == AllFalse
77        let all_false1 = Mask::new_false(5);
78        let all_false2 = Mask::new_false(5);
79        assert_eq!(all_false1, all_false2);
80
81        // Test AllTrue != AllFalse
82        assert_ne!(all_true1, all_false1);
83
84        // Test Values == Values
85        let values1 = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true]));
86        let values2 = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true]));
87        assert_eq!(values1, values2);
88
89        // Test AllTrue != Values (even if all values are true)
90        let all_true_values = Mask::from_buffer(BooleanBuffer::new_set(5));
91        assert_eq!(all_true1, all_true_values); // They should be equal
92
93        // Test AllFalse != Values (even if all values are false)
94        let all_false_values = Mask::from_buffer(BooleanBuffer::new_unset(5));
95        assert_eq!(all_false1, all_false_values); // They should be equal
96    }
97
98    #[test]
99    fn test_mask_eq_reflexive() {
100        // Test that a mask equals itself
101        let mask = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false, true]));
102        assert_eq!(mask, mask);
103    }
104
105    #[test]
106    fn test_mask_eq_symmetric() {
107        // Test that if a == b then b == a
108        let mask1 = Mask::from_indices(5, vec![0, 2, 4]);
109        let mask2 = Mask::from_slices(5, vec![(0, 1), (2, 3), (4, 5)]);
110        assert_eq!(mask1, mask2);
111        assert_eq!(mask2, mask1);
112    }
113
114    #[test]
115    fn test_mask_eq_transitive() {
116        // Test that if a == b and b == c then a == c
117        let mask1 = Mask::from_indices(5, vec![1, 3]);
118        let mask2 = Mask::from_slices(5, vec![(1, 2), (3, 4)]);
119        let mask3 = Mask::from_buffer(BooleanBuffer::from_iter([false, true, false, true, false]));
120
121        assert_eq!(mask1, mask2);
122        assert_eq!(mask2, mask3);
123        assert_eq!(mask1, mask3);
124    }
125
126    #[test]
127    fn test_mask_eq_empty() {
128        // All empty masks become AllFalse regardless of input type
129        let empty1 = Mask::new_true(0);
130        let empty2 = Mask::new_false(0);
131        let empty3 = Mask::from_buffer(BooleanBuffer::new_set(0));
132        let empty4 = Mask::from_buffer(BooleanBuffer::new_unset(0));
133
134        // All should be AllFalse(0) when created from buffer
135        assert!(matches!(empty3, Mask::AllFalse(0)));
136        assert!(matches!(empty4, Mask::AllFalse(0)));
137
138        // new_true(0) is AllTrue(0), new_false(0) is AllFalse(0)
139        assert!(matches!(empty1, Mask::AllTrue(0)));
140        assert!(matches!(empty2, Mask::AllFalse(0)));
141    }
142
143    #[test]
144    fn test_mask_eq_different_representations() {
145        // Test that masks with the same logical values but different internal representations are equal
146        let indices = vec![0, 1, 2, 5, 6, 9];
147        let slices = vec![(0, 3), (5, 7), (9, 10)];
148        let buffer = BooleanBuffer::from_iter([
149            true, true, true, false, false, true, true, false, false, true,
150        ]);
151
152        let mask1 = Mask::from_indices(10, indices);
153        let mask2 = Mask::from_slices(10, slices);
154        let mask3 = Mask::from_buffer(buffer);
155
156        assert_eq!(mask1, mask2);
157        assert_eq!(mask2, mask3);
158        assert_eq!(mask1, mask3);
159    }
160}