1mod scalar;
2
3#[cfg(feature = "dtype-categorical")]
4mod categorical;
5
6use std::ops::{BitAnd, BitOr, Not};
7
8use arrow::array::BooleanArray;
9use arrow::bitmap::{Bitmap, BitmapBuilder};
10use arrow::compute;
11use num_traits::{NumCast, ToPrimitive};
12use polars_compute::comparisons::{TotalEqKernel, TotalOrdKernel};
13
14use crate::prelude::*;
15use crate::series::IsSorted;
16use crate::series::implementations::null::NullChunked;
17use crate::utils::align_chunks_binary;
18
19impl<T> ChunkCompareEq<&ChunkedArray<T>> for ChunkedArray<T>
20where
21 T: PolarsNumericType,
22 T::Array: TotalOrdKernel<Scalar = T::Native> + TotalEqKernel<Scalar = T::Native>,
23{
24 type Item = BooleanChunked;
25
26 fn equal(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
27 match (self.len(), rhs.len()) {
29 (_, 1) => {
30 if let Some(value) = rhs.get(0) {
31 self.equal(value)
32 } else {
33 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
34 }
35 },
36 (1, _) => {
37 if let Some(value) = self.get(0) {
38 rhs.equal(value)
39 } else {
40 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
41 }
42 },
43 _ => arity::binary_mut_values(
44 self,
45 rhs,
46 |a, b| a.tot_eq_kernel(b).into(),
47 PlSmallStr::EMPTY,
48 ),
49 }
50 }
51
52 fn equal_missing(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
53 match (self.len(), rhs.len()) {
55 (_, 1) => {
56 if let Some(value) = rhs.get(0) {
57 self.equal_missing(value)
58 } else {
59 self.is_null()
60 }
61 },
62 (1, _) => {
63 if let Some(value) = self.get(0) {
64 rhs.equal_missing(value)
65 } else {
66 rhs.is_null()
67 }
68 },
69 _ => arity::binary_mut_with_options(
70 self,
71 rhs,
72 |a, b| a.tot_eq_missing_kernel(b).into(),
73 PlSmallStr::EMPTY,
74 ),
75 }
76 }
77
78 fn not_equal(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
79 match (self.len(), rhs.len()) {
81 (_, 1) => {
82 if let Some(value) = rhs.get(0) {
83 self.not_equal(value)
84 } else {
85 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
86 }
87 },
88 (1, _) => {
89 if let Some(value) = self.get(0) {
90 rhs.not_equal(value)
91 } else {
92 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
93 }
94 },
95 _ => arity::binary_mut_values(
96 self,
97 rhs,
98 |a, b| a.tot_ne_kernel(b).into(),
99 PlSmallStr::EMPTY,
100 ),
101 }
102 }
103
104 fn not_equal_missing(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
105 match (self.len(), rhs.len()) {
107 (_, 1) => {
108 if let Some(value) = rhs.get(0) {
109 self.not_equal_missing(value)
110 } else {
111 self.is_not_null()
112 }
113 },
114 (1, _) => {
115 if let Some(value) = self.get(0) {
116 rhs.not_equal_missing(value)
117 } else {
118 rhs.is_not_null()
119 }
120 },
121 _ => arity::binary_mut_with_options(
122 self,
123 rhs,
124 |a, b| a.tot_ne_missing_kernel(b).into(),
125 PlSmallStr::EMPTY,
126 ),
127 }
128 }
129}
130
131impl<T> ChunkCompareIneq<&ChunkedArray<T>> for ChunkedArray<T>
132where
133 T: PolarsNumericType,
134 T::Array: TotalOrdKernel<Scalar = T::Native> + TotalEqKernel<Scalar = T::Native>,
135{
136 type Item = BooleanChunked;
137
138 fn lt(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
139 match (self.len(), rhs.len()) {
141 (_, 1) => {
142 if let Some(value) = rhs.get(0) {
143 self.lt(value)
144 } else {
145 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
146 }
147 },
148 (1, _) => {
149 if let Some(value) = self.get(0) {
150 rhs.gt(value)
151 } else {
152 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
153 }
154 },
155 _ => arity::binary_mut_values(
156 self,
157 rhs,
158 |a, b| a.tot_lt_kernel(b).into(),
159 PlSmallStr::EMPTY,
160 ),
161 }
162 }
163
164 fn lt_eq(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
165 match (self.len(), rhs.len()) {
167 (_, 1) => {
168 if let Some(value) = rhs.get(0) {
169 self.lt_eq(value)
170 } else {
171 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
172 }
173 },
174 (1, _) => {
175 if let Some(value) = self.get(0) {
176 rhs.gt_eq(value)
177 } else {
178 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
179 }
180 },
181 _ => arity::binary_mut_values(
182 self,
183 rhs,
184 |a, b| a.tot_le_kernel(b).into(),
185 PlSmallStr::EMPTY,
186 ),
187 }
188 }
189
190 fn gt(&self, rhs: &Self) -> BooleanChunked {
191 rhs.lt(self)
192 }
193
194 fn gt_eq(&self, rhs: &Self) -> BooleanChunked {
195 rhs.lt_eq(self)
196 }
197}
198
199impl ChunkCompareEq<&NullChunked> for NullChunked {
200 type Item = BooleanChunked;
201
202 fn equal(&self, rhs: &NullChunked) -> Self::Item {
203 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
204 }
205
206 fn equal_missing(&self, rhs: &NullChunked) -> Self::Item {
207 BooleanChunked::full(self.name().clone(), true, get_broadcast_length(self, rhs))
208 }
209
210 fn not_equal(&self, rhs: &NullChunked) -> Self::Item {
211 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
212 }
213
214 fn not_equal_missing(&self, rhs: &NullChunked) -> Self::Item {
215 BooleanChunked::full(self.name().clone(), false, get_broadcast_length(self, rhs))
216 }
217}
218
219impl ChunkCompareIneq<&NullChunked> for NullChunked {
220 type Item = BooleanChunked;
221
222 fn gt(&self, rhs: &NullChunked) -> Self::Item {
223 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
224 }
225
226 fn gt_eq(&self, rhs: &NullChunked) -> Self::Item {
227 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
228 }
229
230 fn lt(&self, rhs: &NullChunked) -> Self::Item {
231 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
232 }
233
234 fn lt_eq(&self, rhs: &NullChunked) -> Self::Item {
235 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
236 }
237}
238
239#[inline]
240fn get_broadcast_length(lhs: &NullChunked, rhs: &NullChunked) -> usize {
241 match (lhs.len(), rhs.len()) {
242 (1, len_r) => len_r,
243 (len_l, 1) => len_l,
244 (len_l, len_r) if len_l == len_r => len_l,
245 _ => panic!("Cannot compare two series of different lengths."),
246 }
247}
248
249impl ChunkCompareEq<&BooleanChunked> for BooleanChunked {
250 type Item = BooleanChunked;
251
252 fn equal(&self, rhs: &BooleanChunked) -> BooleanChunked {
253 match (self.len(), rhs.len()) {
255 (_, 1) => {
256 if let Some(value) = rhs.get(0) {
257 arity::unary_mut_values(self, |arr| arr.tot_eq_kernel_broadcast(&value).into())
258 } else {
259 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
260 }
261 },
262 (1, _) => {
263 if let Some(value) = self.get(0) {
264 arity::unary_mut_values(rhs, |arr| arr.tot_eq_kernel_broadcast(&value).into())
265 } else {
266 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
267 }
268 },
269 _ => arity::binary_mut_values(
270 self,
271 rhs,
272 |a, b| a.tot_eq_kernel(b).into(),
273 PlSmallStr::EMPTY,
274 ),
275 }
276 }
277
278 fn equal_missing(&self, rhs: &BooleanChunked) -> BooleanChunked {
279 match (self.len(), rhs.len()) {
281 (_, 1) => {
282 if let Some(value) = rhs.get(0) {
283 arity::unary_mut_with_options(self, |arr| {
284 arr.tot_eq_missing_kernel_broadcast(&value).into()
285 })
286 } else {
287 self.is_null()
288 }
289 },
290 (1, _) => {
291 if let Some(value) = self.get(0) {
292 arity::unary_mut_with_options(rhs, |arr| {
293 arr.tot_eq_missing_kernel_broadcast(&value).into()
294 })
295 } else {
296 rhs.is_null()
297 }
298 },
299 _ => arity::binary_mut_with_options(
300 self,
301 rhs,
302 |a, b| a.tot_eq_missing_kernel(b).into(),
303 PlSmallStr::EMPTY,
304 ),
305 }
306 }
307
308 fn not_equal(&self, rhs: &BooleanChunked) -> BooleanChunked {
309 match (self.len(), rhs.len()) {
311 (_, 1) => {
312 if let Some(value) = rhs.get(0) {
313 arity::unary_mut_values(self, |arr| arr.tot_ne_kernel_broadcast(&value).into())
314 } else {
315 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
316 }
317 },
318 (1, _) => {
319 if let Some(value) = self.get(0) {
320 arity::unary_mut_values(rhs, |arr| arr.tot_ne_kernel_broadcast(&value).into())
321 } else {
322 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
323 }
324 },
325 _ => arity::binary_mut_values(
326 self,
327 rhs,
328 |a, b| a.tot_ne_kernel(b).into(),
329 PlSmallStr::EMPTY,
330 ),
331 }
332 }
333
334 fn not_equal_missing(&self, rhs: &BooleanChunked) -> BooleanChunked {
335 match (self.len(), rhs.len()) {
337 (_, 1) => {
338 if let Some(value) = rhs.get(0) {
339 arity::unary_mut_with_options(self, |arr| {
340 arr.tot_ne_missing_kernel_broadcast(&value).into()
341 })
342 } else {
343 self.is_not_null()
344 }
345 },
346 (1, _) => {
347 if let Some(value) = self.get(0) {
348 arity::unary_mut_with_options(rhs, |arr| {
349 arr.tot_ne_missing_kernel_broadcast(&value).into()
350 })
351 } else {
352 rhs.is_not_null()
353 }
354 },
355 _ => arity::binary_mut_with_options(
356 self,
357 rhs,
358 |a, b| a.tot_ne_missing_kernel(b).into(),
359 PlSmallStr::EMPTY,
360 ),
361 }
362 }
363}
364
365impl ChunkCompareIneq<&BooleanChunked> for BooleanChunked {
366 type Item = BooleanChunked;
367
368 fn lt(&self, rhs: &BooleanChunked) -> BooleanChunked {
369 match (self.len(), rhs.len()) {
371 (_, 1) => {
372 if let Some(value) = rhs.get(0) {
373 arity::unary_mut_values(self, |arr| arr.tot_lt_kernel_broadcast(&value).into())
374 } else {
375 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
376 }
377 },
378 (1, _) => {
379 if let Some(value) = self.get(0) {
380 arity::unary_mut_values(rhs, |arr| arr.tot_gt_kernel_broadcast(&value).into())
381 } else {
382 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
383 }
384 },
385 _ => arity::binary_mut_values(
386 self,
387 rhs,
388 |a, b| a.tot_lt_kernel(b).into(),
389 PlSmallStr::EMPTY,
390 ),
391 }
392 }
393
394 fn lt_eq(&self, rhs: &BooleanChunked) -> BooleanChunked {
395 match (self.len(), rhs.len()) {
397 (_, 1) => {
398 if let Some(value) = rhs.get(0) {
399 arity::unary_mut_values(self, |arr| arr.tot_le_kernel_broadcast(&value).into())
400 } else {
401 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
402 }
403 },
404 (1, _) => {
405 if let Some(value) = self.get(0) {
406 arity::unary_mut_values(rhs, |arr| arr.tot_ge_kernel_broadcast(&value).into())
407 } else {
408 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
409 }
410 },
411 _ => arity::binary_mut_values(
412 self,
413 rhs,
414 |a, b| a.tot_le_kernel(b).into(),
415 PlSmallStr::EMPTY,
416 ),
417 }
418 }
419
420 fn gt(&self, rhs: &Self) -> BooleanChunked {
421 rhs.lt(self)
422 }
423
424 fn gt_eq(&self, rhs: &Self) -> BooleanChunked {
425 rhs.lt_eq(self)
426 }
427}
428
429impl ChunkCompareEq<&StringChunked> for StringChunked {
430 type Item = BooleanChunked;
431
432 fn equal(&self, rhs: &StringChunked) -> BooleanChunked {
433 self.as_binary().equal(&rhs.as_binary())
434 }
435
436 fn equal_missing(&self, rhs: &StringChunked) -> BooleanChunked {
437 self.as_binary().equal_missing(&rhs.as_binary())
438 }
439
440 fn not_equal(&self, rhs: &StringChunked) -> BooleanChunked {
441 self.as_binary().not_equal(&rhs.as_binary())
442 }
443
444 fn not_equal_missing(&self, rhs: &StringChunked) -> BooleanChunked {
445 self.as_binary().not_equal_missing(&rhs.as_binary())
446 }
447}
448
449impl ChunkCompareIneq<&StringChunked> for StringChunked {
450 type Item = BooleanChunked;
451
452 fn gt(&self, rhs: &StringChunked) -> BooleanChunked {
453 self.as_binary().gt(&rhs.as_binary())
454 }
455
456 fn gt_eq(&self, rhs: &StringChunked) -> BooleanChunked {
457 self.as_binary().gt_eq(&rhs.as_binary())
458 }
459
460 fn lt(&self, rhs: &StringChunked) -> BooleanChunked {
461 self.as_binary().lt(&rhs.as_binary())
462 }
463
464 fn lt_eq(&self, rhs: &StringChunked) -> BooleanChunked {
465 self.as_binary().lt_eq(&rhs.as_binary())
466 }
467}
468
469macro_rules! binary_eq_ineq_impl {
470 ($($ca:ident),+) => {
471 $(
472 impl ChunkCompareEq<&$ca> for $ca {
473 type Item = BooleanChunked;
474
475 fn equal(&self, rhs: &$ca) -> BooleanChunked {
476 match (self.len(), rhs.len()) {
478 (_, 1) => {
479 if let Some(value) = rhs.get(0) {
480 self.equal(value)
481 } else {
482 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
483 }
484 },
485 (1, _) => {
486 if let Some(value) = self.get(0) {
487 rhs.equal(value)
488 } else {
489 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
490 }
491 },
492 _ => arity::binary_mut_values(
493 self,
494 rhs,
495 |a, b| a.tot_eq_kernel(b).into(),
496 PlSmallStr::EMPTY,
497 ),
498 }
499 }
500
501 fn equal_missing(&self, rhs: &$ca) -> BooleanChunked {
502 match (self.len(), rhs.len()) {
504 (_, 1) => {
505 if let Some(value) = rhs.get(0) {
506 self.equal_missing(value)
507 } else {
508 self.is_null()
509 }
510 },
511 (1, _) => {
512 if let Some(value) = self.get(0) {
513 rhs.equal_missing(value)
514 } else {
515 rhs.is_null()
516 }
517 },
518 _ => arity::binary_mut_with_options(
519 self,
520 rhs,
521 |a, b| a.tot_eq_missing_kernel(b).into(),
522 PlSmallStr::EMPTY,
523 ),
524 }
525 }
526
527 fn not_equal(&self, rhs: &$ca) -> BooleanChunked {
528 match (self.len(), rhs.len()) {
530 (_, 1) => {
531 if let Some(value) = rhs.get(0) {
532 self.not_equal(value)
533 } else {
534 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
535 }
536 },
537 (1, _) => {
538 if let Some(value) = self.get(0) {
539 rhs.not_equal(value)
540 } else {
541 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
542 }
543 },
544 _ => arity::binary_mut_values(
545 self,
546 rhs,
547 |a, b| a.tot_ne_kernel(b).into(),
548 PlSmallStr::EMPTY,
549 ),
550 }
551 }
552
553 fn not_equal_missing(&self, rhs: &$ca) -> BooleanChunked {
554 match (self.len(), rhs.len()) {
556 (_, 1) => {
557 if let Some(value) = rhs.get(0) {
558 self.not_equal_missing(value)
559 } else {
560 self.is_not_null()
561 }
562 },
563 (1, _) => {
564 if let Some(value) = self.get(0) {
565 rhs.not_equal_missing(value)
566 } else {
567 rhs.is_not_null()
568 }
569 },
570 _ => arity::binary_mut_with_options(
571 self,
572 rhs,
573 |a, b| a.tot_ne_missing_kernel(b).into(),
574 PlSmallStr::EMPTY,
575 ),
576 }
577 }
578 }
579
580 impl ChunkCompareIneq<&$ca> for $ca {
581 type Item = BooleanChunked;
582
583 fn lt(&self, rhs: &$ca) -> BooleanChunked {
584 match (self.len(), rhs.len()) {
586 (_, 1) => {
587 if let Some(value) = rhs.get(0) {
588 self.lt(value)
589 } else {
590 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
591 }
592 },
593 (1, _) => {
594 if let Some(value) = self.get(0) {
595 rhs.gt(value)
596 } else {
597 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
598 }
599 },
600 _ => arity::binary_mut_values(
601 self,
602 rhs,
603 |a, b| a.tot_lt_kernel(b).into(),
604 PlSmallStr::EMPTY,
605 ),
606 }
607 }
608
609 fn lt_eq(&self, rhs: &$ca) -> BooleanChunked {
610 match (self.len(), rhs.len()) {
612 (_, 1) => {
613 if let Some(value) = rhs.get(0) {
614 self.lt_eq(value)
615 } else {
616 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
617 }
618 },
619 (1, _) => {
620 if let Some(value) = self.get(0) {
621 rhs.gt_eq(value)
622 } else {
623 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
624 }
625 },
626 _ => arity::binary_mut_values(
627 self,
628 rhs,
629 |a, b| a.tot_le_kernel(b).into(),
630 PlSmallStr::EMPTY,
631 ),
632 }
633 }
634
635 fn gt(&self, rhs: &Self) -> BooleanChunked {
636 rhs.lt(self)
637 }
638
639 fn gt_eq(&self, rhs: &Self) -> BooleanChunked {
640 rhs.lt_eq(self)
641 }
642 }
643 )+
644 };
645}
646
647binary_eq_ineq_impl!(BinaryChunked, BinaryOffsetChunked);
648
649fn _list_comparison_helper<F, B>(
650 lhs: &ListChunked,
651 rhs: &ListChunked,
652 op: F,
653 broadcast_op: B,
654 missing: bool,
655 is_ne: bool,
656) -> BooleanChunked
657where
658 F: Fn(&ListArray<i64>, &ListArray<i64>) -> Bitmap,
659 B: Fn(&ListArray<i64>, &Box<dyn Array>) -> Bitmap,
660{
661 match (lhs.len(), rhs.len()) {
662 (_, 1) => {
663 let right = rhs
664 .downcast_iter()
665 .find(|x| !x.is_empty())
666 .unwrap()
667 .as_any()
668 .downcast_ref::<ListArray<i64>>()
669 .unwrap();
670
671 if !right.validity().is_none_or(|v| v.get(0).unwrap()) {
672 if missing {
673 if is_ne {
674 return lhs.is_not_null();
675 } else {
676 return lhs.is_null();
677 }
678 } else {
679 return BooleanChunked::full_null(PlSmallStr::EMPTY, lhs.len());
680 }
681 }
682
683 let values = right.values().sliced(
684 (*right.offsets().first()).try_into().unwrap(),
685 right.offsets().range().try_into().unwrap(),
686 );
687
688 if missing {
689 arity::unary_mut_with_options(lhs, |a| broadcast_op(a, &values).into())
690 } else {
691 arity::unary_mut_values(lhs, |a| broadcast_op(a, &values).into())
692 }
693 },
694 (1, _) => {
695 let left = lhs
696 .downcast_iter()
697 .find(|x| !x.is_empty())
698 .unwrap()
699 .as_any()
700 .downcast_ref::<ListArray<i64>>()
701 .unwrap();
702
703 if !left.validity().is_none_or(|v| v.get(0).unwrap()) {
704 if missing {
705 if is_ne {
706 return rhs.is_not_null();
707 } else {
708 return rhs.is_null();
709 }
710 } else {
711 return BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len());
712 }
713 }
714
715 let values = left.values().sliced(
716 (*left.offsets().first()).try_into().unwrap(),
717 left.offsets().range().try_into().unwrap(),
718 );
719
720 if missing {
721 arity::unary_mut_with_options(rhs, |a| broadcast_op(a, &values).into())
722 } else {
723 arity::unary_mut_values(rhs, |a| broadcast_op(a, &values).into())
724 }
725 },
726 _ => {
727 if missing {
728 arity::binary_mut_with_options(lhs, rhs, |a, b| op(a, b).into(), PlSmallStr::EMPTY)
729 } else {
730 arity::binary_mut_values(lhs, rhs, |a, b| op(a, b).into(), PlSmallStr::EMPTY)
731 }
732 },
733 }
734}
735
736impl ChunkCompareEq<&ListChunked> for ListChunked {
737 type Item = BooleanChunked;
738 fn equal(&self, rhs: &ListChunked) -> BooleanChunked {
739 _list_comparison_helper(
740 self,
741 rhs,
742 TotalEqKernel::tot_eq_kernel,
743 TotalEqKernel::tot_eq_kernel_broadcast,
744 false,
745 false,
746 )
747 }
748
749 fn equal_missing(&self, rhs: &ListChunked) -> BooleanChunked {
750 _list_comparison_helper(
751 self,
752 rhs,
753 TotalEqKernel::tot_eq_missing_kernel,
754 TotalEqKernel::tot_eq_missing_kernel_broadcast,
755 true,
756 false,
757 )
758 }
759
760 fn not_equal(&self, rhs: &ListChunked) -> BooleanChunked {
761 _list_comparison_helper(
762 self,
763 rhs,
764 TotalEqKernel::tot_ne_kernel,
765 TotalEqKernel::tot_ne_kernel_broadcast,
766 false,
767 true,
768 )
769 }
770
771 fn not_equal_missing(&self, rhs: &ListChunked) -> BooleanChunked {
772 _list_comparison_helper(
773 self,
774 rhs,
775 TotalEqKernel::tot_ne_missing_kernel,
776 TotalEqKernel::tot_ne_missing_kernel_broadcast,
777 true,
778 true,
779 )
780 }
781}
782
783#[cfg(feature = "dtype-struct")]
784fn struct_helper<F, R>(
785 a: &StructChunked,
786 b: &StructChunked,
787 op: F,
788 reduce: R,
789 op_is_ne: bool,
790 is_missing: bool,
791) -> BooleanChunked
792where
793 F: Fn(&Series, &Series) -> BooleanChunked,
794 R: Fn(BooleanChunked, BooleanChunked) -> BooleanChunked,
795{
796 let len_a = a.len();
797 let len_b = b.len();
798 let broadcasts = len_a == 1 || len_b == 1;
799 if (a.len() != b.len() && !broadcasts) || a.struct_fields().len() != b.struct_fields().len() {
800 BooleanChunked::full(PlSmallStr::EMPTY, op_is_ne, a.len())
801 } else {
802 let (a, b) = align_chunks_binary(a, b);
803
804 let mut out = a
805 .fields_as_series()
806 .iter()
807 .zip(b.fields_as_series().iter())
808 .map(|(l, r)| op(l, r))
809 .reduce(&reduce)
810 .unwrap_or_else(|| BooleanChunked::full(PlSmallStr::EMPTY, !op_is_ne, a.len()));
811
812 if is_missing && (a.has_nulls() || b.has_nulls()) {
813 let default =
816 || BooleanChunked::with_chunk(PlSmallStr::EMPTY, BooleanArray::from_slice([true]));
817 let validity_to_ca = |x| unsafe {
818 BooleanChunked::with_chunk(
819 PlSmallStr::EMPTY,
820 BooleanArray::from_inner_unchecked(ArrowDataType::Boolean, x, None),
821 )
822 };
823
824 let a_s = a.rechunk_validity().map_or_else(default, validity_to_ca);
825 let b_s = b.rechunk_validity().map_or_else(default, validity_to_ca);
826
827 let shared_validity = (&a_s).bitand(&b_s);
828 let valid_nested = if op_is_ne {
829 (shared_validity).bitand(out)
830 } else {
831 (!shared_validity).bitor(out)
832 };
833 out = reduce(op(&a_s.into_series(), &b_s.into_series()), valid_nested);
834 }
835
836 if !is_missing && (a.has_nulls() || b.has_nulls()) {
837 let mut a = a;
838 let mut b = b;
839
840 if broadcasts {
841 if a.len() == 1 {
842 a = std::borrow::Cow::Owned(a.new_from_index(0, b.len()));
843 }
844 if b.len() == 1 {
845 b = std::borrow::Cow::Owned(b.new_from_index(0, a.len()));
846 }
847 }
848
849 let mut a = a.into_owned();
850 a.zip_outer_validity(&b);
851 unsafe {
852 let mut new_null_count = 0;
853 for (arr, a) in out.downcast_iter_mut().zip(a.downcast_iter()) {
854 arr.set_validity(a.validity().cloned());
855 new_null_count += arr.null_count();
856 }
857 out.set_null_count(new_null_count);
858 }
859 }
860
861 out
862 }
863}
864
865#[cfg(feature = "dtype-struct")]
866impl ChunkCompareEq<&StructChunked> for StructChunked {
867 type Item = BooleanChunked;
868 fn equal(&self, rhs: &StructChunked) -> BooleanChunked {
869 struct_helper(
870 self,
871 rhs,
872 |l, r| l.equal_missing(r).unwrap(),
873 |a, b| a.bitand(b),
874 false,
875 false,
876 )
877 }
878
879 fn equal_missing(&self, rhs: &StructChunked) -> BooleanChunked {
880 struct_helper(
881 self,
882 rhs,
883 |l, r| l.equal_missing(r).unwrap(),
884 |a, b| a.bitand(b),
885 false,
886 true,
887 )
888 }
889
890 fn not_equal(&self, rhs: &StructChunked) -> BooleanChunked {
891 struct_helper(
892 self,
893 rhs,
894 |l, r| l.not_equal_missing(r).unwrap(),
895 |a, b| a.bitor(b),
896 true,
897 false,
898 )
899 }
900
901 fn not_equal_missing(&self, rhs: &StructChunked) -> BooleanChunked {
902 struct_helper(
903 self,
904 rhs,
905 |l, r| l.not_equal_missing(r).unwrap(),
906 |a, b| a.bitor(b),
907 true,
908 true,
909 )
910 }
911}
912
913#[cfg(feature = "dtype-array")]
914fn _array_comparison_helper<F, B>(
915 lhs: &ArrayChunked,
916 rhs: &ArrayChunked,
917 op: F,
918 broadcast_op: B,
919 missing: bool,
920 is_ne: bool,
921) -> BooleanChunked
922where
923 F: Fn(&FixedSizeListArray, &FixedSizeListArray) -> Bitmap,
924 B: Fn(&FixedSizeListArray, &Box<dyn Array>) -> Bitmap,
925{
926 match (lhs.len(), rhs.len()) {
927 (_, 1) => {
928 let right = rhs
929 .downcast_iter()
930 .find(|x| !x.is_empty())
931 .unwrap()
932 .as_any()
933 .downcast_ref::<FixedSizeListArray>()
934 .unwrap();
935
936 if !right.validity().is_none_or(|v| v.get(0).unwrap()) {
937 if missing {
938 if is_ne {
939 return lhs.is_not_null();
940 } else {
941 return lhs.is_null();
942 }
943 } else {
944 return BooleanChunked::full_null(PlSmallStr::EMPTY, lhs.len());
945 }
946 }
947
948 if missing {
949 arity::unary_mut_with_options(lhs, |a| broadcast_op(a, right.values()).into())
950 } else {
951 arity::unary_mut_values(lhs, |a| broadcast_op(a, right.values()).into())
952 }
953 },
954 (1, _) => {
955 let left = lhs
956 .downcast_iter()
957 .find(|x| !x.is_empty())
958 .unwrap()
959 .as_any()
960 .downcast_ref::<FixedSizeListArray>()
961 .unwrap();
962
963 if !left.validity().is_none_or(|v| v.get(0).unwrap()) {
964 if missing {
965 if is_ne {
966 return rhs.is_not_null();
967 } else {
968 return rhs.is_null();
969 }
970 } else {
971 return BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len());
972 }
973 }
974
975 if missing {
976 arity::unary_mut_with_options(rhs, |a| broadcast_op(a, left.values()).into())
977 } else {
978 arity::unary_mut_values(rhs, |a| broadcast_op(a, left.values()).into())
979 }
980 },
981 _ => {
982 if missing {
983 arity::binary_mut_with_options(lhs, rhs, |a, b| op(a, b).into(), PlSmallStr::EMPTY)
984 } else {
985 arity::binary_mut_values(lhs, rhs, |a, b| op(a, b).into(), PlSmallStr::EMPTY)
986 }
987 },
988 }
989}
990
991#[cfg(feature = "dtype-array")]
992impl ChunkCompareEq<&ArrayChunked> for ArrayChunked {
993 type Item = BooleanChunked;
994 fn equal(&self, rhs: &ArrayChunked) -> BooleanChunked {
995 _array_comparison_helper(
996 self,
997 rhs,
998 TotalEqKernel::tot_eq_kernel,
999 TotalEqKernel::tot_eq_kernel_broadcast,
1000 false,
1001 false,
1002 )
1003 }
1004
1005 fn equal_missing(&self, rhs: &ArrayChunked) -> BooleanChunked {
1006 _array_comparison_helper(
1007 self,
1008 rhs,
1009 TotalEqKernel::tot_eq_missing_kernel,
1010 TotalEqKernel::tot_eq_missing_kernel_broadcast,
1011 true,
1012 false,
1013 )
1014 }
1015
1016 fn not_equal(&self, rhs: &ArrayChunked) -> BooleanChunked {
1017 _array_comparison_helper(
1018 self,
1019 rhs,
1020 TotalEqKernel::tot_ne_kernel,
1021 TotalEqKernel::tot_ne_kernel_broadcast,
1022 false,
1023 true,
1024 )
1025 }
1026
1027 fn not_equal_missing(&self, rhs: &ArrayChunked) -> Self::Item {
1028 _array_comparison_helper(
1029 self,
1030 rhs,
1031 TotalEqKernel::tot_ne_missing_kernel,
1032 TotalEqKernel::tot_ne_missing_kernel_broadcast,
1033 true,
1034 true,
1035 )
1036 }
1037}
1038
1039impl Not for &BooleanChunked {
1040 type Output = BooleanChunked;
1041
1042 fn not(self) -> Self::Output {
1043 let chunks = self.downcast_iter().map(compute::boolean::not);
1044 ChunkedArray::from_chunk_iter(self.name().clone(), chunks)
1045 }
1046}
1047
1048impl Not for BooleanChunked {
1049 type Output = BooleanChunked;
1050
1051 fn not(self) -> Self::Output {
1052 (&self).not()
1053 }
1054}
1055
1056impl BooleanChunked {
1057 pub fn any(&self) -> bool {
1061 self.downcast_iter().any(compute::boolean::any)
1062 }
1063
1064 pub fn all(&self) -> bool {
1068 self.downcast_iter().all(compute::boolean::all)
1069 }
1070
1071 pub fn any_kleene(&self) -> Option<bool> {
1076 let mut result = Some(false);
1077 for arr in self.downcast_iter() {
1078 match compute::boolean_kleene::any(arr) {
1079 Some(true) => return Some(true),
1080 None => result = None,
1081 _ => (),
1082 };
1083 }
1084 result
1085 }
1086
1087 pub fn all_kleene(&self) -> Option<bool> {
1092 let mut result = Some(true);
1093 for arr in self.downcast_iter() {
1094 match compute::boolean_kleene::all(arr) {
1095 Some(false) => return Some(false),
1096 None => result = None,
1097 _ => (),
1098 };
1099 }
1100 result
1101 }
1102}
1103
1104pub(crate) trait ChunkEqualElement {
1106 unsafe fn equal_element(&self, _idx_self: usize, _idx_other: usize, _other: &Series) -> bool {
1113 unimplemented!()
1114 }
1115}
1116
1117impl<T> ChunkEqualElement for ChunkedArray<T>
1118where
1119 T: PolarsNumericType,
1120{
1121 unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
1122 let ca_other = other.as_ref().as_ref();
1123 debug_assert!(self.dtype() == other.dtype());
1124 let ca_other = &*(ca_other as *const ChunkedArray<T>);
1125 self.get_unchecked(idx_self)
1127 .tot_eq(&ca_other.get_unchecked(idx_other))
1128 }
1129}
1130
1131impl ChunkEqualElement for BooleanChunked {
1132 unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
1133 let ca_other = other.as_ref().as_ref();
1134 debug_assert!(self.dtype() == other.dtype());
1135 let ca_other = &*(ca_other as *const BooleanChunked);
1136 self.get_unchecked(idx_self) == ca_other.get_unchecked(idx_other)
1137 }
1138}
1139
1140impl ChunkEqualElement for StringChunked {
1141 unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
1142 let ca_other = other.as_ref().as_ref();
1143 debug_assert!(self.dtype() == other.dtype());
1144 let ca_other = &*(ca_other as *const StringChunked);
1145 self.get_unchecked(idx_self) == ca_other.get_unchecked(idx_other)
1146 }
1147}
1148
1149impl ChunkEqualElement for BinaryChunked {
1150 unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
1151 let ca_other = other.as_ref().as_ref();
1152 debug_assert!(self.dtype() == other.dtype());
1153 let ca_other = &*(ca_other as *const BinaryChunked);
1154 self.get_unchecked(idx_self) == ca_other.get_unchecked(idx_other)
1155 }
1156}
1157
1158impl ChunkEqualElement for BinaryOffsetChunked {
1159 unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
1160 let ca_other = other.as_ref().as_ref();
1161 debug_assert!(self.dtype() == other.dtype());
1162 let ca_other = &*(ca_other as *const BinaryOffsetChunked);
1163 self.get_unchecked(idx_self) == ca_other.get_unchecked(idx_other)
1164 }
1165}
1166
1167impl ChunkEqualElement for ListChunked {}
1168#[cfg(feature = "dtype-array")]
1169impl ChunkEqualElement for ArrayChunked {}
1170
1171#[cfg(test)]
1172#[cfg_attr(feature = "nightly", allow(clippy::manual_repeat_n))] mod test {
1174 use std::iter::repeat_n;
1175
1176 use super::super::test::get_chunked_array;
1177 use crate::prelude::*;
1178
1179 pub(crate) fn create_two_chunked() -> (Int32Chunked, Int32Chunked) {
1180 let mut a1 = Int32Chunked::new(PlSmallStr::from_static("a"), &[1, 2, 3]);
1181 let a2 = Int32Chunked::new(PlSmallStr::from_static("a"), &[4, 5, 6]);
1182 let a3 = Int32Chunked::new(PlSmallStr::from_static("a"), &[1, 2, 3, 4, 5, 6]);
1183 a1.append(&a2).unwrap();
1184 (a1, a3)
1185 }
1186
1187 #[test]
1188 fn test_bitwise_ops() {
1189 let a = BooleanChunked::new(PlSmallStr::from_static("a"), &[true, false, false]);
1190 let b = BooleanChunked::new(
1191 PlSmallStr::from_static("b"),
1192 &[Some(true), Some(true), None],
1193 );
1194 assert_eq!(Vec::from(&a | &b), &[Some(true), Some(true), None]);
1195 assert_eq!(Vec::from(&a & &b), &[Some(true), Some(false), Some(false)]);
1196 assert_eq!(Vec::from(!b), &[Some(false), Some(false), None]);
1197 }
1198
1199 #[test]
1200 fn test_compare_chunk_diff() {
1201 let (a1, a2) = create_two_chunked();
1202
1203 assert_eq!(
1204 a1.equal(&a2).into_iter().collect::<Vec<_>>(),
1205 repeat_n(Some(true), 6).collect::<Vec<_>>()
1206 );
1207 assert_eq!(
1208 a2.equal(&a1).into_iter().collect::<Vec<_>>(),
1209 repeat_n(Some(true), 6).collect::<Vec<_>>()
1210 );
1211 assert_eq!(
1212 a1.not_equal(&a2).into_iter().collect::<Vec<_>>(),
1213 repeat_n(Some(false), 6).collect::<Vec<_>>()
1214 );
1215 assert_eq!(
1216 a2.not_equal(&a1).into_iter().collect::<Vec<_>>(),
1217 repeat_n(Some(false), 6).collect::<Vec<_>>()
1218 );
1219 assert_eq!(
1220 a1.gt(&a2).into_iter().collect::<Vec<_>>(),
1221 repeat_n(Some(false), 6).collect::<Vec<_>>()
1222 );
1223 assert_eq!(
1224 a2.gt(&a1).into_iter().collect::<Vec<_>>(),
1225 repeat_n(Some(false), 6).collect::<Vec<_>>()
1226 );
1227 assert_eq!(
1228 a1.gt_eq(&a2).into_iter().collect::<Vec<_>>(),
1229 repeat_n(Some(true), 6).collect::<Vec<_>>()
1230 );
1231 assert_eq!(
1232 a2.gt_eq(&a1).into_iter().collect::<Vec<_>>(),
1233 repeat_n(Some(true), 6).collect::<Vec<_>>()
1234 );
1235 assert_eq!(
1236 a1.lt_eq(&a2).into_iter().collect::<Vec<_>>(),
1237 repeat_n(Some(true), 6).collect::<Vec<_>>()
1238 );
1239 assert_eq!(
1240 a2.lt_eq(&a1).into_iter().collect::<Vec<_>>(),
1241 repeat_n(Some(true), 6).collect::<Vec<_>>()
1242 );
1243 assert_eq!(
1244 a1.lt(&a2).into_iter().collect::<Vec<_>>(),
1245 repeat_n(Some(false), 6).collect::<Vec<_>>()
1246 );
1247 assert_eq!(
1248 a2.lt(&a1).into_iter().collect::<Vec<_>>(),
1249 repeat_n(Some(false), 6).collect::<Vec<_>>()
1250 );
1251 }
1252
1253 #[test]
1254 fn test_equal_chunks() {
1255 let a1 = get_chunked_array();
1256 let a2 = get_chunked_array();
1257
1258 assert_eq!(
1259 a1.equal(&a2).into_iter().collect::<Vec<_>>(),
1260 repeat_n(Some(true), 3).collect::<Vec<_>>()
1261 );
1262 assert_eq!(
1263 a2.equal(&a1).into_iter().collect::<Vec<_>>(),
1264 repeat_n(Some(true), 3).collect::<Vec<_>>()
1265 );
1266 assert_eq!(
1267 a1.not_equal(&a2).into_iter().collect::<Vec<_>>(),
1268 repeat_n(Some(false), 3).collect::<Vec<_>>()
1269 );
1270 assert_eq!(
1271 a2.not_equal(&a1).into_iter().collect::<Vec<_>>(),
1272 repeat_n(Some(false), 3).collect::<Vec<_>>()
1273 );
1274 assert_eq!(
1275 a1.gt(&a2).into_iter().collect::<Vec<_>>(),
1276 repeat_n(Some(false), 3).collect::<Vec<_>>()
1277 );
1278 assert_eq!(
1279 a2.gt(&a1).into_iter().collect::<Vec<_>>(),
1280 repeat_n(Some(false), 3).collect::<Vec<_>>()
1281 );
1282 assert_eq!(
1283 a1.gt_eq(&a2).into_iter().collect::<Vec<_>>(),
1284 repeat_n(Some(true), 3).collect::<Vec<_>>()
1285 );
1286 assert_eq!(
1287 a2.gt_eq(&a1).into_iter().collect::<Vec<_>>(),
1288 repeat_n(Some(true), 3).collect::<Vec<_>>()
1289 );
1290 assert_eq!(
1291 a1.lt_eq(&a2).into_iter().collect::<Vec<_>>(),
1292 repeat_n(Some(true), 3).collect::<Vec<_>>()
1293 );
1294 assert_eq!(
1295 a2.lt_eq(&a1).into_iter().collect::<Vec<_>>(),
1296 repeat_n(Some(true), 3).collect::<Vec<_>>()
1297 );
1298 assert_eq!(
1299 a1.lt(&a2).into_iter().collect::<Vec<_>>(),
1300 repeat_n(Some(false), 3).collect::<Vec<_>>()
1301 );
1302 assert_eq!(
1303 a2.lt(&a1).into_iter().collect::<Vec<_>>(),
1304 repeat_n(Some(false), 3).collect::<Vec<_>>()
1305 );
1306 }
1307
1308 #[test]
1309 fn test_null_handling() {
1310 let a1: Int32Chunked = [Some(1), None, Some(3)].iter().copied().collect();
1316 let a2: Int32Chunked = [Some(1), Some(2), Some(3)].iter().copied().collect();
1317
1318 let mut a2_2chunks: Int32Chunked = [Some(1), Some(2)].iter().copied().collect();
1319 a2_2chunks
1320 .append(&[Some(3)].iter().copied().collect())
1321 .unwrap();
1322
1323 assert_eq!(
1324 a1.equal(&a2).into_iter().collect::<Vec<_>>(),
1325 a1.equal(&a2_2chunks).into_iter().collect::<Vec<_>>()
1326 );
1327
1328 assert_eq!(
1329 a1.not_equal(&a2).into_iter().collect::<Vec<_>>(),
1330 a1.not_equal(&a2_2chunks).into_iter().collect::<Vec<_>>()
1331 );
1332 assert_eq!(
1333 a1.not_equal(&a2).into_iter().collect::<Vec<_>>(),
1334 a2_2chunks.not_equal(&a1).into_iter().collect::<Vec<_>>()
1335 );
1336
1337 assert_eq!(
1338 a1.gt(&a2).into_iter().collect::<Vec<_>>(),
1339 a1.gt(&a2_2chunks).into_iter().collect::<Vec<_>>()
1340 );
1341 assert_eq!(
1342 a1.gt(&a2).into_iter().collect::<Vec<_>>(),
1343 a2_2chunks.gt(&a1).into_iter().collect::<Vec<_>>()
1344 );
1345
1346 assert_eq!(
1347 a1.gt_eq(&a2).into_iter().collect::<Vec<_>>(),
1348 a1.gt_eq(&a2_2chunks).into_iter().collect::<Vec<_>>()
1349 );
1350 assert_eq!(
1351 a1.gt_eq(&a2).into_iter().collect::<Vec<_>>(),
1352 a2_2chunks.gt_eq(&a1).into_iter().collect::<Vec<_>>()
1353 );
1354
1355 assert_eq!(
1356 a1.lt_eq(&a2).into_iter().collect::<Vec<_>>(),
1357 a1.lt_eq(&a2_2chunks).into_iter().collect::<Vec<_>>()
1358 );
1359 assert_eq!(
1360 a1.lt_eq(&a2).into_iter().collect::<Vec<_>>(),
1361 a2_2chunks.lt_eq(&a1).into_iter().collect::<Vec<_>>()
1362 );
1363
1364 assert_eq!(
1365 a1.lt(&a2).into_iter().collect::<Vec<_>>(),
1366 a1.lt(&a2_2chunks).into_iter().collect::<Vec<_>>()
1367 );
1368 assert_eq!(
1369 a1.lt(&a2).into_iter().collect::<Vec<_>>(),
1370 a2_2chunks.lt(&a1).into_iter().collect::<Vec<_>>()
1371 );
1372 }
1373
1374 #[test]
1375 fn test_left_right() {
1376 let a1: Int32Chunked = [Some(1), Some(2)].iter().copied().collect();
1379 let a1 = a1.slice(1, 1);
1380 let a2: Int32Chunked = [Some(2)].iter().copied().collect();
1381 assert_eq!(a1.equal(&a2).sum(), a2.equal(&a1).sum());
1382 assert_eq!(a1.not_equal(&a2).sum(), a2.not_equal(&a1).sum());
1383 assert_eq!(a1.gt(&a2).sum(), a2.gt(&a1).sum());
1384 assert_eq!(a1.lt(&a2).sum(), a2.lt(&a1).sum());
1385 assert_eq!(a1.lt_eq(&a2).sum(), a2.lt_eq(&a1).sum());
1386 assert_eq!(a1.gt_eq(&a2).sum(), a2.gt_eq(&a1).sum());
1387
1388 let a1: StringChunked = ["a", "b"].iter().copied().collect();
1389 let a1 = a1.slice(1, 1);
1390 let a2: StringChunked = ["b"].iter().copied().collect();
1391 assert_eq!(a1.equal(&a2).sum(), a2.equal(&a1).sum());
1392 assert_eq!(a1.not_equal(&a2).sum(), a2.not_equal(&a1).sum());
1393 assert_eq!(a1.gt(&a2).sum(), a2.gt(&a1).sum());
1394 assert_eq!(a1.lt(&a2).sum(), a2.lt(&a1).sum());
1395 assert_eq!(a1.lt_eq(&a2).sum(), a2.lt_eq(&a1).sum());
1396 assert_eq!(a1.gt_eq(&a2).sum(), a2.gt_eq(&a1).sum());
1397 }
1398
1399 #[test]
1400 fn test_kleene() {
1401 let a = BooleanChunked::new(PlSmallStr::EMPTY, &[Some(true), Some(false), None]);
1402 let trues = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[true, true, true]);
1403 let falses = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[false, false, false]);
1404
1405 let c = &a | &trues;
1406 assert_eq!(Vec::from(&c), &[Some(true), Some(true), Some(true)]);
1407
1408 let c = &a | &falses;
1409 assert_eq!(Vec::from(&c), &[Some(true), Some(false), None])
1410 }
1411
1412 #[test]
1413 fn list_broadcasting_lists() {
1414 let s_el = Series::new(PlSmallStr::EMPTY, &[1, 2, 3]);
1415 let s_lhs = Series::new(PlSmallStr::EMPTY, &[s_el.clone(), s_el.clone()]);
1416 let s_rhs = Series::new(PlSmallStr::EMPTY, std::slice::from_ref(&s_el));
1417
1418 let result = s_lhs.list().unwrap().equal(s_rhs.list().unwrap());
1419 assert_eq!(result.len(), 2);
1420 assert!(result.all());
1421 }
1422
1423 #[test]
1424 fn test_broadcasting_bools() {
1425 let a = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[true, false, true]);
1426 let true_ = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[true]);
1427 let false_ = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[false]);
1428
1429 let out = a.equal(&true_);
1430 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1431 let out = true_.equal(&a);
1432 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1433 let out = a.equal(&false_);
1434 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1435 let out = false_.equal(&a);
1436 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1437
1438 let out = a.not_equal(&true_);
1439 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1440 let out = true_.not_equal(&a);
1441 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1442 let out = a.not_equal(&false_);
1443 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1444 let out = false_.not_equal(&a);
1445 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1446
1447 let out = a.gt(&true_);
1448 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1449 let out = true_.gt(&a);
1450 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1451 let out = a.gt(&false_);
1452 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1453 let out = false_.gt(&a);
1454 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1455
1456 let out = a.gt_eq(&true_);
1457 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1458 let out = true_.gt_eq(&a);
1459 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1460 let out = a.gt_eq(&false_);
1461 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1462 let out = false_.gt_eq(&a);
1463 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1464
1465 let out = a.lt(&true_);
1466 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1467 let out = true_.lt(&a);
1468 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1469 let out = a.lt(&false_);
1470 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1471 let out = false_.lt(&a);
1472 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1473
1474 let out = a.lt_eq(&true_);
1475 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1476 let out = true_.lt_eq(&a);
1477 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1478 let out = a.lt_eq(&false_);
1479 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1480 let out = false_.lt_eq(&a);
1481 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1482
1483 let a =
1484 BooleanChunked::from_slice_options(PlSmallStr::EMPTY, &[Some(true), Some(false), None]);
1485 let all_true = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[true, true, true]);
1486 let all_false = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[false, false, false]);
1487 let out = a.equal(&true_);
1488 assert_eq!(Vec::from(&out), &[Some(true), Some(false), None]);
1489 let out = a.not_equal(&true_);
1490 assert_eq!(Vec::from(&out), &[Some(false), Some(true), None]);
1491
1492 let out = a.equal(&all_true);
1493 assert_eq!(Vec::from(&out), &[Some(true), Some(false), None]);
1494 let out = a.not_equal(&all_true);
1495 assert_eq!(Vec::from(&out), &[Some(false), Some(true), None]);
1496 let out = a.equal(&false_);
1497 assert_eq!(Vec::from(&out), &[Some(false), Some(true), None]);
1498 let out = a.not_equal(&false_);
1499 assert_eq!(Vec::from(&out), &[Some(true), Some(false), None]);
1500 let out = a.equal(&all_false);
1501 assert_eq!(Vec::from(&out), &[Some(false), Some(true), None]);
1502 let out = a.not_equal(&all_false);
1503 assert_eq!(Vec::from(&out), &[Some(true), Some(false), None]);
1504 }
1505
1506 #[test]
1507 fn test_broadcasting_numeric() {
1508 let a = Int32Chunked::from_slice(PlSmallStr::EMPTY, &[1, 2, 3]);
1509 let one = Int32Chunked::from_slice(PlSmallStr::EMPTY, &[1]);
1510 let three = Int32Chunked::from_slice(PlSmallStr::EMPTY, &[3]);
1511
1512 let out = a.equal(&one);
1513 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(false)]);
1514 let out = one.equal(&a);
1515 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(false)]);
1516 let out = a.equal(&three);
1517 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(true)]);
1518 let out = three.equal(&a);
1519 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(true)]);
1520
1521 let out = a.not_equal(&one);
1522 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(true)]);
1523 let out = one.not_equal(&a);
1524 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(true)]);
1525 let out = a.not_equal(&three);
1526 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(false)]);
1527 let out = three.not_equal(&a);
1528 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(false)]);
1529
1530 let out = a.gt(&one);
1531 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(true)]);
1532 let out = one.gt(&a);
1533 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1534 let out = a.gt(&three);
1535 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1536 let out = three.gt(&a);
1537 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(false)]);
1538
1539 let out = a.lt(&one);
1540 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1541 let out = one.lt(&a);
1542 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(true)]);
1543 let out = a.lt(&three);
1544 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(false)]);
1545 let out = three.lt(&a);
1546 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1547
1548 let out = a.gt_eq(&one);
1549 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1550 let out = one.gt_eq(&a);
1551 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(false)]);
1552 let out = a.gt_eq(&three);
1553 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(true)]);
1554 let out = three.gt_eq(&a);
1555 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1556
1557 let out = a.lt_eq(&one);
1558 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(false)]);
1559 let out = one.lt_eq(&a);
1560 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1561 let out = a.lt_eq(&three);
1562 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1563 let out = three.lt_eq(&a);
1564 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(true)]);
1565 }
1566}