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 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 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 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 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 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 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 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 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}