splinter_rs/
splinter_ops.rs

1use std::{
2    mem,
3    ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Deref, Sub, SubAssign},
4};
5
6use crate::{CowSplinter, Cut, PartitionRead, Splinter, SplinterRef};
7
8impl<B: Deref<Target = [u8]>> PartialEq<SplinterRef<B>> for Splinter {
9    #[inline]
10    fn eq(&self, other: &SplinterRef<B>) -> bool {
11        self.inner() == &other.load_unchecked()
12    }
13}
14
15impl<B: Deref<Target = [u8]>> PartialEq<CowSplinter<B>> for Splinter {
16    fn eq(&self, other: &CowSplinter<B>) -> bool {
17        match other {
18            CowSplinter::Ref(splinter_ref) => self.eq(splinter_ref),
19            CowSplinter::Owned(splinter) => self.eq(splinter),
20        }
21    }
22}
23
24impl Cut for Splinter {
25    type Out = Self;
26
27    fn cut(&mut self, rhs: &Self) -> Self::Out {
28        Self::new(self.inner_mut().cut(rhs.inner()))
29    }
30}
31
32impl<B: Deref<Target = [u8]>> Cut<SplinterRef<B>> for Splinter {
33    type Out = Self;
34
35    fn cut(&mut self, rhs: &SplinterRef<B>) -> Self::Out {
36        Self::new(self.inner_mut().cut(&rhs.load_unchecked()))
37    }
38}
39
40impl<B: Deref<Target = [u8]>> Cut<CowSplinter<B>> for Splinter {
41    type Out = Self;
42
43    fn cut(&mut self, rhs: &CowSplinter<B>) -> Self::Out {
44        match rhs {
45            CowSplinter::Ref(splinter_ref) => self.cut(splinter_ref),
46            CowSplinter::Owned(splinter) => self.cut(splinter),
47        }
48    }
49}
50
51macro_rules! binary_bitop {
52    ($BitOp:tt, $bitop:ident, $bitassign:path) => {
53        impl $BitOp<Splinter> for Splinter {
54            type Output = Splinter;
55            fn $bitop(mut self, rhs: Splinter) -> Self::Output {
56                $bitassign(&mut self, rhs);
57                self
58            }
59        }
60        impl $BitOp<&Splinter> for Splinter {
61            type Output = Splinter;
62            fn $bitop(mut self, rhs: &Splinter) -> Self::Output {
63                $bitassign(&mut self, rhs);
64                self
65            }
66        }
67        impl<B: Deref<Target = [u8]>> $BitOp<SplinterRef<B>> for Splinter {
68            type Output = Splinter;
69            fn $bitop(mut self, rhs: SplinterRef<B>) -> Self::Output {
70                $bitassign(&mut self, rhs);
71                self
72            }
73        }
74        impl<B: Deref<Target = [u8]>> $BitOp<&SplinterRef<B>> for Splinter {
75            type Output = Splinter;
76            fn $bitop(mut self, rhs: &SplinterRef<B>) -> Self::Output {
77                $bitassign(&mut self, rhs);
78                self
79            }
80        }
81        impl<B: Deref<Target = [u8]>> $BitOp<SplinterRef<B>> for &Splinter {
82            type Output = Splinter;
83            fn $bitop(self, rhs: SplinterRef<B>) -> Self::Output {
84                $BitOp::$bitop(self.clone(), rhs)
85            }
86        }
87        impl<B: Deref<Target = [u8]>> $BitOp<&SplinterRef<B>> for &Splinter {
88            type Output = Splinter;
89            fn $bitop(self, rhs: &SplinterRef<B>) -> Self::Output {
90                $BitOp::$bitop(self.clone(), rhs)
91            }
92        }
93    };
94}
95
96macro_rules! unary_bitassign {
97    ($BitOpAssign:tt, $bitassign:ident) => {
98        impl $BitOpAssign<&Splinter> for Splinter {
99            fn $bitassign(&mut self, rhs: &Splinter) {
100                $BitOpAssign::$bitassign(self.inner_mut(), rhs.inner())
101            }
102        }
103        impl<B: Deref<Target = [u8]>> $BitOpAssign<SplinterRef<B>> for Splinter {
104            fn $bitassign(&mut self, rhs: SplinterRef<B>) {
105                $BitOpAssign::$bitassign(self.inner_mut(), &rhs.load_unchecked())
106            }
107        }
108        impl<B: Deref<Target = [u8]>> $BitOpAssign<&SplinterRef<B>> for Splinter {
109            fn $bitassign(&mut self, rhs: &SplinterRef<B>) {
110                $BitOpAssign::$bitassign(self.inner_mut(), &rhs.load_unchecked())
111            }
112        }
113        impl<B: Deref<Target = [u8]>> $BitOpAssign<CowSplinter<B>> for Splinter {
114            fn $bitassign(&mut self, rhs: CowSplinter<B>) {
115                match rhs {
116                    CowSplinter::Ref(splinter_ref) => $BitOpAssign::$bitassign(self, splinter_ref),
117                    CowSplinter::Owned(splinter) => $BitOpAssign::$bitassign(self, splinter),
118                }
119            }
120        }
121        impl<B: Deref<Target = [u8]>> $BitOpAssign<&CowSplinter<B>> for Splinter {
122            fn $bitassign(&mut self, rhs: &CowSplinter<B>) {
123                match rhs {
124                    CowSplinter::Ref(splinter_ref) => $BitOpAssign::$bitassign(self, splinter_ref),
125                    CowSplinter::Owned(splinter) => $BitOpAssign::$bitassign(self, splinter),
126                }
127            }
128        }
129    };
130}
131
132binary_bitop!(BitOr, bitor, BitOrAssign::bitor_assign);
133unary_bitassign!(BitOrAssign, bitor_assign);
134
135binary_bitop!(BitAnd, bitand, BitAndAssign::bitand_assign);
136unary_bitassign!(BitAndAssign, bitand_assign);
137
138binary_bitop!(BitXor, bitxor, BitXorAssign::bitxor_assign);
139unary_bitassign!(BitXorAssign, bitxor_assign);
140
141binary_bitop!(Sub, sub, SubAssign::sub_assign);
142unary_bitassign!(SubAssign, sub_assign);
143
144impl BitOr<&Splinter> for &Splinter {
145    type Output = Splinter;
146    fn bitor(self, rhs: &Splinter) -> Self::Output {
147        // merge into the larger set
148        if rhs.cardinality() > self.cardinality() {
149            let mut result = rhs.clone();
150            result.inner_mut().bitor_assign(self.inner());
151            result
152        } else {
153            let mut result = self.clone();
154            result.inner_mut().bitor_assign(rhs.inner());
155            result
156        }
157    }
158}
159
160impl BitOr<Splinter> for &Splinter {
161    type Output = Splinter;
162    fn bitor(self, mut rhs: Splinter) -> Self::Output {
163        rhs |= self;
164        rhs
165    }
166}
167
168impl BitOrAssign<Splinter> for Splinter {
169    fn bitor_assign(&mut self, mut rhs: Splinter) {
170        // merge into the larger set
171        if rhs.cardinality() > self.cardinality() {
172            mem::swap(self, &mut rhs);
173        }
174        self.inner_mut().bitor_assign(rhs.inner())
175    }
176}
177
178impl BitAnd<&Splinter> for &Splinter {
179    type Output = Splinter;
180    fn bitand(self, rhs: &Splinter) -> Self::Output {
181        // intersect into the smaller set
182        if rhs.cardinality() < self.cardinality() {
183            let mut result = rhs.clone();
184            result.inner_mut().bitand_assign(self.inner());
185            result
186        } else {
187            let mut result = self.clone();
188            result.inner_mut().bitand_assign(rhs.inner());
189            result
190        }
191    }
192}
193
194impl BitAnd<Splinter> for &Splinter {
195    type Output = Splinter;
196    fn bitand(self, mut rhs: Splinter) -> Self::Output {
197        rhs &= self;
198        rhs
199    }
200}
201
202impl BitAndAssign<Splinter> for Splinter {
203    fn bitand_assign(&mut self, mut rhs: Splinter) {
204        // intersect into the smaller set
205        if rhs.cardinality() < self.cardinality() {
206            mem::swap(self, &mut rhs);
207        }
208        self.inner_mut().bitand_assign(rhs.inner())
209    }
210}
211
212impl BitXor<&Splinter> for &Splinter {
213    type Output = Splinter;
214    fn bitxor(self, rhs: &Splinter) -> Self::Output {
215        let mut result = self.clone();
216        result.inner_mut().bitxor_assign(rhs.inner());
217        result
218    }
219}
220
221impl BitXor<Splinter> for &Splinter {
222    type Output = Splinter;
223    fn bitxor(self, mut rhs: Splinter) -> Self::Output {
224        rhs ^= self;
225        rhs
226    }
227}
228
229impl BitXorAssign<Splinter> for Splinter {
230    fn bitxor_assign(&mut self, rhs: Splinter) {
231        self.inner_mut().bitxor_assign(rhs.inner())
232    }
233}
234
235impl Sub<&Splinter> for &Splinter {
236    type Output = Splinter;
237    fn sub(self, rhs: &Splinter) -> Self::Output {
238        let mut result = self.clone();
239        result.inner_mut().sub_assign(rhs.inner());
240        result
241    }
242}
243
244impl Sub<Splinter> for &Splinter {
245    type Output = Splinter;
246    fn sub(self, rhs: Splinter) -> Self::Output {
247        self - &rhs
248    }
249}
250
251impl SubAssign<Splinter> for Splinter {
252    fn sub_assign(&mut self, rhs: Splinter) {
253        self.inner_mut().sub_assign(rhs.inner())
254    }
255}
256
257#[cfg(test)]
258mod tests {
259    use std::ops::{
260        BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign,
261    };
262
263    use itertools::Itertools;
264    use proptest::collection::{hash_set, vec};
265    use proptest::proptest;
266
267    use crate::{Optimizable, Splinter, testutil::mksplinter, traits::Cut};
268
269    macro_rules! test_bitop {
270        ($test_name:ident, $op_method:ident, $op_assign_method:ident, $hashset_method:ident) => {
271            proptest! {
272                #[test]
273                fn $test_name(
274                    optimize: bool,
275                    a in hash_set(0u32..16384, 0..1024),
276                    b in hash_set(0u32..16384, 0..1024),
277                ) {
278                    let expected: Splinter = a.$hashset_method(&b).copied().collect();
279
280                    let mut a = Splinter::from_iter(a);
281                    let b = Splinter::from_iter(b);
282
283                    if optimize {
284                        a.optimize();
285                    }
286
287                    // test all combinations of refs
288                    assert_eq!((&a).$op_method(&b), expected, "&a, &b");
289                    assert_eq!((&a).$op_method(b.clone()), expected, "&a, b");
290                    assert_eq!(a.clone().$op_method(&b), expected, "a, &b");
291                    assert_eq!(a.clone().$op_method(b.clone()), expected, "a, b");
292
293                    // assignment operator
294                    let mut c = a.clone();
295                    c.$op_assign_method(b.clone());
296                    assert_eq!(c, expected, "c assign b");
297
298                    let mut c = a.clone();
299                    c.$op_assign_method(&b);
300                    assert_eq!(c, expected, "c assign &b");
301
302                    // do it all again but against a splinter ref
303                    let b = b.encode_to_splinter_ref();
304
305                    assert_eq!((&a).$op_method(&b), expected, "&a, &bref");
306                    assert_eq!((&a).$op_method(b.clone()), expected, "&a, bref");
307                    assert_eq!(a.clone().$op_method(&b), expected, "a, &bref");
308                    assert_eq!(a.clone().$op_method(b.clone()), expected, "a, bref");
309
310                    // assignment operator
311                    let mut c = a.clone();
312                    c.$op_assign_method(b.clone());
313                    assert_eq!(c, expected, "c assign bref");
314
315                    let mut c = a.clone();
316                    c.$op_assign_method(&b);
317                    assert_eq!(c, expected, "c assign &bref");
318                }
319            }
320        };
321    }
322
323    proptest! {
324        #[test]
325        fn test_splinter_equality_proptest(values in vec(0u32..16384, 0..1024)) {
326            let mut a = mksplinter(&values);
327            a.optimize();
328            let b = mksplinter(&values);
329            assert!(a == b)
330        }
331
332        #[test]
333        fn test_splinter_equality_ref_proptest(values in vec(0u32..16384, 0..1024)) {
334            let mut a = mksplinter(&values);
335            a.optimize();
336            let b = mksplinter(&values).encode_to_splinter_ref();
337            assert!(a == b)
338        }
339
340        #[test]
341        fn test_splinter_equality_proptest_2(
342            a in vec(0u32..16384, 0..1024),
343            b in vec(0u32..16384, 0..1024),
344        ) {
345            let expected = itertools::equal(a.iter().sorted().dedup(), b.iter().sorted().dedup());
346
347            let mut a = mksplinter(&a);
348            a.optimize();
349            let b = mksplinter(&b);
350
351            assert!((a == b) == expected)
352        }
353
354        #[test]
355        fn test_splinter_equality_ref_proptest_2(
356            a in vec(0u32..16384, 0..1024),
357            b in vec(0u32..16384, 0..1024),
358        ) {
359            let expected = itertools::equal(a.iter().sorted().dedup(), b.iter().sorted().dedup());
360
361            let mut a = mksplinter(&a);
362            a.optimize();
363            let b = mksplinter(&b).encode_to_splinter_ref();
364
365            assert!((a == b) == expected)
366        }
367
368        #[test]
369        fn test_bitor_assign_proptest(
370            optimize: bool,
371            a in hash_set(0u32..16384, 0..1024),
372            b in hash_set(0u32..16384, 0..1024),
373        ) {
374            let mut set: Splinter = a.iter().copied().collect();
375            let other: Splinter = b.iter().copied().collect();
376
377            if optimize {
378                set.optimize();
379            }
380
381            let expected: Splinter = a.union(&b).copied().collect();
382            set |= other;
383            assert!(set == expected)
384        }
385
386        #[test]
387        fn test_cut_proptest(
388            optimize: bool,
389            a in hash_set(0u32..16384, 0..1024),
390            b in hash_set(0u32..16384, 0..1024),
391        ) {
392            let mut source: Splinter = a.iter().copied().collect();
393            let other: Splinter = b.iter().copied().collect();
394
395            if optimize {
396                source.optimize();
397            }
398
399            let expected_intersection: Splinter = a.intersection(&b).copied().collect();
400            let expected_remaining: Splinter = a.difference(&b).copied().collect();
401
402            let actual_intersection = source.cut(&other);
403
404            assert_eq!(actual_intersection,expected_intersection);
405            assert_eq!(source,expected_remaining);
406        }
407
408        #[test]
409        fn test_bitor_ref_proptest(
410            optimize: bool,
411            a in hash_set(0u32..16384, 0..1024),
412            b in hash_set(0u32..16384, 0..1024),
413        ) {
414            let mut set: Splinter = a.iter().copied().collect();
415            let other_ref = Splinter::from_iter(b.clone()).encode_to_splinter_ref();
416
417            if optimize {
418                set.optimize();
419            }
420
421            let expected: Splinter = a.union(&b).copied().collect();
422            set |= other_ref;
423            assert!(set == expected)
424        }
425
426        #[test]
427        fn test_cut_ref_proptest(
428            optimize: bool,
429            a in hash_set(0u32..16384, 0..1024),
430            b in hash_set(0u32..16384, 0..1024),
431        ) {
432            let mut source: Splinter = a.iter().copied().collect();
433            let other_ref = Splinter::from_iter(b.clone()).encode_to_splinter_ref();
434
435            if optimize {
436                source.optimize();
437            }
438
439            let expected_intersection: Splinter = a.intersection(&b).copied().collect();
440            let expected_remaining: Splinter = a.difference(&b).copied().collect();
441
442            let actual_intersection = source.cut(&other_ref);
443
444            assert_eq!(actual_intersection,expected_intersection);
445            assert_eq!(source,expected_remaining);
446        }
447    }
448
449    test_bitop!(test_bitor, bitor, bitor_assign, union);
450    test_bitop!(test_bitand, bitand, bitand_assign, intersection);
451    test_bitop!(test_bitxor, bitxor, bitxor_assign, symmetric_difference);
452    test_bitop!(test_sub, sub, sub_assign, difference);
453}