1use arrow_array::cast::*;
21use arrow_array::iterator::ArrayIter;
22use arrow_array::*;
23use arrow_buffer::{ArrowNativeType, NullBuffer};
24use arrow_data::bit_iterator::try_for_each_valid_idx;
25use arrow_schema::*;
26use std::borrow::BorrowMut;
27use std::cmp::{self, Ordering};
28use std::ops::{BitAnd, BitOr, BitXor};
29use types::ByteViewType;
30
31trait NumericAccumulator<T: ArrowNativeTypeOp>: Copy + Default {
33 fn accumulate(&mut self, value: T);
35 fn accumulate_nullable(&mut self, value: T, valid: bool);
38 fn merge(&mut self, other: Self);
40 fn finish(&mut self) -> T;
42}
43
44#[inline(always)]
47fn select<T: Copy>(m: bool, a: T, b: T) -> T {
48 if m { a } else { b }
49}
50
51#[derive(Clone, Copy)]
52struct SumAccumulator<T: ArrowNativeTypeOp> {
53 sum: T,
54}
55
56impl<T: ArrowNativeTypeOp> Default for SumAccumulator<T> {
57 fn default() -> Self {
58 Self { sum: T::ZERO }
59 }
60}
61
62impl<T: ArrowNativeTypeOp> NumericAccumulator<T> for SumAccumulator<T> {
63 fn accumulate(&mut self, value: T) {
64 self.sum = self.sum.add_wrapping(value);
65 }
66
67 fn accumulate_nullable(&mut self, value: T, valid: bool) {
68 let sum = self.sum;
69 self.sum = select(valid, sum.add_wrapping(value), sum)
70 }
71
72 fn merge(&mut self, other: Self) {
73 self.sum = self.sum.add_wrapping(other.sum);
74 }
75
76 fn finish(&mut self) -> T {
77 self.sum
78 }
79}
80
81#[derive(Clone, Copy)]
82struct MinAccumulator<T: ArrowNativeTypeOp> {
83 min: T,
84}
85
86impl<T: ArrowNativeTypeOp> Default for MinAccumulator<T> {
87 fn default() -> Self {
88 Self {
89 min: T::MAX_TOTAL_ORDER,
90 }
91 }
92}
93
94impl<T: ArrowNativeTypeOp> NumericAccumulator<T> for MinAccumulator<T> {
95 fn accumulate(&mut self, value: T) {
96 let min = self.min;
97 self.min = select(value.is_lt(min), value, min);
98 }
99
100 fn accumulate_nullable(&mut self, value: T, valid: bool) {
101 let min = self.min;
102 let is_lt = valid & value.is_lt(min);
103 self.min = select(is_lt, value, min);
104 }
105
106 fn merge(&mut self, other: Self) {
107 self.accumulate(other.min)
108 }
109
110 fn finish(&mut self) -> T {
111 self.min
112 }
113}
114
115#[derive(Clone, Copy)]
116struct MaxAccumulator<T: ArrowNativeTypeOp> {
117 max: T,
118}
119
120impl<T: ArrowNativeTypeOp> Default for MaxAccumulator<T> {
121 fn default() -> Self {
122 Self {
123 max: T::MIN_TOTAL_ORDER,
124 }
125 }
126}
127
128impl<T: ArrowNativeTypeOp> NumericAccumulator<T> for MaxAccumulator<T> {
129 fn accumulate(&mut self, value: T) {
130 let max = self.max;
131 self.max = select(value.is_gt(max), value, max);
132 }
133
134 fn accumulate_nullable(&mut self, value: T, valid: bool) {
135 let max = self.max;
136 let is_gt = value.is_gt(max) & valid;
137 self.max = select(is_gt, value, max);
138 }
139
140 fn merge(&mut self, other: Self) {
141 self.accumulate(other.max)
142 }
143
144 fn finish(&mut self) -> T {
145 self.max
146 }
147}
148
149fn reduce_accumulators<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
150 mut acc: [A; LANES],
151) -> A {
152 assert!(LANES > 0 && LANES.is_power_of_two());
153 let mut len = LANES;
154
155 while len >= 2 {
158 let mid = len / 2;
159 let (h, t) = acc[..len].split_at_mut(mid);
160
161 for i in 0..mid {
162 h[i].merge(t[i]);
163 }
164 len /= 2;
165 }
166 acc[0]
167}
168
169#[inline(always)]
170fn aggregate_nonnull_chunk<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
171 acc: &mut [A; LANES],
172 values: &[T; LANES],
173) {
174 for i in 0..LANES {
175 acc[i].accumulate(values[i]);
176 }
177}
178
179#[inline(always)]
180fn aggregate_nullable_chunk<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
181 acc: &mut [A; LANES],
182 values: &[T; LANES],
183 validity: u64,
184) {
185 let mut bit = 1;
186 for i in 0..LANES {
187 acc[i].accumulate_nullable(values[i], (validity & bit) != 0);
188 bit <<= 1;
189 }
190}
191
192fn aggregate_nonnull_simple<T: ArrowNativeTypeOp, A: NumericAccumulator<T>>(values: &[T]) -> T {
193 values
194 .iter()
195 .copied()
196 .fold(A::default(), |mut a, b| {
197 a.accumulate(b);
198 a
199 })
200 .finish()
201}
202
203#[inline(never)]
204fn aggregate_nonnull_lanes<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
205 values: &[T],
206) -> T {
207 let mut acc = [A::default(); LANES];
210 let mut chunks = values.chunks_exact(LANES);
211 chunks.borrow_mut().for_each(|chunk| {
212 aggregate_nonnull_chunk(&mut acc, chunk[..LANES].try_into().unwrap());
213 });
214
215 let remainder = chunks.remainder();
216 for i in 0..remainder.len() {
217 acc[i].accumulate(remainder[i]);
218 }
219
220 reduce_accumulators(acc).finish()
221}
222
223#[inline(never)]
224fn aggregate_nullable_lanes<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
225 values: &[T],
226 validity: &NullBuffer,
227) -> T {
228 assert!(LANES > 0 && 64 % LANES == 0);
229 assert_eq!(values.len(), validity.len());
230
231 let mut acc = [A::default(); LANES];
233 let mut values_chunks = values.chunks_exact(64);
235 let validity_chunks = validity.inner().bit_chunks();
236 let mut validity_chunks_iter = validity_chunks.iter();
237
238 values_chunks.borrow_mut().for_each(|chunk| {
239 let mut validity = unsafe { validity_chunks_iter.next().unwrap_unchecked() };
241 chunk.chunks_exact(LANES).for_each(|chunk| {
243 aggregate_nullable_chunk(&mut acc, chunk[..LANES].try_into().unwrap(), validity);
244 validity >>= LANES;
245 });
246 });
247
248 let remainder = values_chunks.remainder();
249 if !remainder.is_empty() {
250 let mut validity = validity_chunks.remainder_bits();
251
252 let mut remainder_chunks = remainder.chunks_exact(LANES);
253 remainder_chunks.borrow_mut().for_each(|chunk| {
254 aggregate_nullable_chunk(&mut acc, chunk[..LANES].try_into().unwrap(), validity);
255 validity >>= LANES;
256 });
257
258 let remainder = remainder_chunks.remainder();
259 if !remainder.is_empty() {
260 let mut bit = 1;
261 for i in 0..remainder.len() {
262 acc[i].accumulate_nullable(remainder[i], (validity & bit) != 0);
263 bit <<= 1;
264 }
265 }
266 }
267
268 reduce_accumulators(acc).finish()
269}
270
271const PREFERRED_VECTOR_SIZE: usize =
274 if cfg!(all(target_arch = "x86_64", target_feature = "avx512f")) {
275 64
276 } else if cfg!(all(target_arch = "x86_64", target_feature = "avx")) {
277 32
278 } else {
279 16
280 };
281
282const PREFERRED_VECTOR_SIZE_NON_NULL: usize = PREFERRED_VECTOR_SIZE * 2;
284
285fn aggregate<T: ArrowNativeTypeOp, P: ArrowPrimitiveType<Native = T>, A: NumericAccumulator<T>>(
288 array: &PrimitiveArray<P>,
289) -> Option<T> {
290 let null_count = array.null_count();
291 if null_count == array.len() {
292 return None;
293 }
294 let values = array.values().as_ref();
295 match array.nulls() {
296 Some(nulls) if null_count > 0 => {
297 match PREFERRED_VECTOR_SIZE / std::mem::size_of::<T>() {
300 64 => Some(aggregate_nullable_lanes::<T, A, 64>(values, nulls)),
301 32 => Some(aggregate_nullable_lanes::<T, A, 32>(values, nulls)),
302 16 => Some(aggregate_nullable_lanes::<T, A, 16>(values, nulls)),
303 8 => Some(aggregate_nullable_lanes::<T, A, 8>(values, nulls)),
304 4 => Some(aggregate_nullable_lanes::<T, A, 4>(values, nulls)),
305 2 => Some(aggregate_nullable_lanes::<T, A, 2>(values, nulls)),
306 _ => Some(aggregate_nullable_lanes::<T, A, 1>(values, nulls)),
307 }
308 }
309 _ => {
310 let is_float = matches!(
311 array.data_type(),
312 DataType::Float16 | DataType::Float32 | DataType::Float64
313 );
314 if is_float {
315 match PREFERRED_VECTOR_SIZE_NON_NULL / std::mem::size_of::<T>() {
316 64 => Some(aggregate_nonnull_lanes::<T, A, 64>(values)),
317 32 => Some(aggregate_nonnull_lanes::<T, A, 32>(values)),
318 16 => Some(aggregate_nonnull_lanes::<T, A, 16>(values)),
319 8 => Some(aggregate_nonnull_lanes::<T, A, 8>(values)),
320 4 => Some(aggregate_nonnull_lanes::<T, A, 4>(values)),
321 2 => Some(aggregate_nonnull_lanes::<T, A, 2>(values)),
322 _ => Some(aggregate_nonnull_simple::<T, A>(values)),
323 }
324 } else {
325 Some(aggregate_nonnull_simple::<T, A>(values))
328 }
329 }
330 }
331}
332
333pub fn min_boolean(array: &BooleanArray) -> Option<bool> {
343 if array.null_count() == array.len() {
345 return None;
346 }
347
348 match array.nulls() {
350 None => {
351 let bit_chunks = array.values().bit_chunks();
352 if bit_chunks.iter().any(|x| {
353 x != u64::MAX
355 }) {
356 return Some(false);
357 }
358 if bit_chunks.remainder_bits().count_ones() as usize != bit_chunks.remainder_len() {
360 Some(false)
361 } else {
362 Some(true)
363 }
364 }
365 Some(nulls) => {
366 let validity_chunks = nulls.inner().bit_chunks();
367 let value_chunks = array.values().bit_chunks();
368
369 if value_chunks
370 .iter()
371 .zip(validity_chunks.iter())
372 .any(|(value, validity)| {
373 (!value & validity) != 0
376 })
377 {
378 return Some(false);
379 }
380
381 if (!value_chunks.remainder_bits() & validity_chunks.remainder_bits()) != 0 {
383 Some(false)
384 } else {
385 Some(true)
386 }
387 }
388 }
389}
390
391pub fn max_boolean(array: &BooleanArray) -> Option<bool> {
401 if array.null_count() == array.len() {
403 return None;
404 }
405
406 match array.nulls() {
408 None => array
409 .values()
410 .bit_chunks()
411 .iter_padded()
412 .map(|x| x != 0)
414 .find(|b| *b)
415 .or(Some(false)),
416 Some(nulls) => {
417 let validity_chunks = nulls.inner().bit_chunks().iter_padded();
418 let value_chunks = array.values().bit_chunks().iter_padded();
419 value_chunks
420 .zip(validity_chunks)
421 .map(|(value_bits, validity_bits)| (value_bits & validity_bits) != 0)
423 .find(|b| *b)
424 .or(Some(false))
425 }
426 }
427}
428
429fn min_max_helper<T, A: ArrayAccessor<Item = T>, F>(array: A, cmp: F) -> Option<T>
431where
432 F: Fn(&T, &T) -> bool,
433{
434 let null_count = array.null_count();
435 if null_count == array.len() {
436 None
437 } else if null_count == 0 {
438 (0..array.len())
442 .map(|i| unsafe { array.value_unchecked(i) })
443 .reduce(|acc, item| if cmp(&acc, &item) { item } else { acc })
444 } else {
445 let nulls = array.nulls().unwrap();
446 unsafe {
447 let idx = nulls.valid_indices().reduce(|acc_idx, idx| {
448 let acc = array.value_unchecked(acc_idx);
449 let item = array.value_unchecked(idx);
450 if cmp(&acc, &item) { idx } else { acc_idx }
451 });
452 idx.map(|idx| array.value_unchecked(idx))
453 }
454 }
455}
456
457fn min_max_view_helper<T: ByteViewType>(
462 array: &GenericByteViewArray<T>,
463 swap_cond: cmp::Ordering,
464) -> Option<&T::Native> {
465 let null_count = array.null_count();
466 if null_count == array.len() {
467 None
468 } else if null_count == 0 {
469 let target_idx = (0..array.len()).reduce(|acc, item| {
470 let cmp = unsafe { GenericByteViewArray::compare_unchecked(array, item, array, acc) };
472 if cmp == swap_cond { item } else { acc }
473 });
474 unsafe { target_idx.map(|idx| array.value_unchecked(idx)) }
476 } else {
477 let nulls = array.nulls().unwrap();
478
479 let target_idx = nulls.valid_indices().reduce(|acc_idx, idx| {
480 let cmp =
481 unsafe { GenericByteViewArray::compare_unchecked(array, idx, array, acc_idx) };
482 if cmp == swap_cond { idx } else { acc_idx }
483 });
484
485 unsafe { target_idx.map(|idx| array.value_unchecked(idx)) }
487 }
488}
489
490pub fn max_binary<T: OffsetSizeTrait>(array: &GenericBinaryArray<T>) -> Option<&[u8]> {
492 min_max_helper::<&[u8], _, _>(array, |a, b| *a < *b)
493}
494
495pub fn max_binary_view(array: &BinaryViewArray) -> Option<&[u8]> {
497 min_max_view_helper(array, Ordering::Greater)
498}
499
500pub fn max_fixed_size_binary(array: &FixedSizeBinaryArray) -> Option<&[u8]> {
502 min_max_helper::<&[u8], _, _>(array, |a, b| *a < *b)
503}
504
505pub fn min_binary<T: OffsetSizeTrait>(array: &GenericBinaryArray<T>) -> Option<&[u8]> {
507 min_max_helper::<&[u8], _, _>(array, |a, b| *a > *b)
508}
509
510pub fn min_binary_view(array: &BinaryViewArray) -> Option<&[u8]> {
512 min_max_view_helper(array, Ordering::Less)
513}
514
515pub fn min_fixed_size_binary(array: &FixedSizeBinaryArray) -> Option<&[u8]> {
517 min_max_helper::<&[u8], _, _>(array, |a, b| *a > *b)
518}
519
520pub fn max_string<T: OffsetSizeTrait>(array: &GenericStringArray<T>) -> Option<&str> {
522 min_max_helper::<&str, _, _>(array, |a, b| *a < *b)
523}
524
525pub fn max_string_view(array: &StringViewArray) -> Option<&str> {
527 min_max_view_helper(array, Ordering::Greater)
528}
529
530pub fn min_string<T: OffsetSizeTrait>(array: &GenericStringArray<T>) -> Option<&str> {
532 min_max_helper::<&str, _, _>(array, |a, b| *a > *b)
533}
534
535pub fn min_string_view(array: &StringViewArray) -> Option<&str> {
537 min_max_view_helper(array, Ordering::Less)
538}
539
540pub fn sum_array<T, A: ArrayAccessor<Item = T::Native>>(array: A) -> Option<T::Native>
545where
546 T: ArrowNumericType,
547 T::Native: ArrowNativeTypeOp,
548{
549 match array.data_type() {
550 DataType::Dictionary(_, _) => {
551 let null_count = array.null_count();
552
553 if null_count == array.len() {
554 return None;
555 }
556
557 let iter = ArrayIter::new(array);
558 let sum = iter
559 .into_iter()
560 .fold(T::default_value(), |accumulator, value| {
561 if let Some(value) = value {
562 accumulator.add_wrapping(value)
563 } else {
564 accumulator
565 }
566 });
567
568 Some(sum)
569 }
570 _ => sum::<T>(as_primitive_array(&array)),
571 }
572}
573
574pub fn sum_array_checked<T, A: ArrayAccessor<Item = T::Native>>(
579 array: A,
580) -> Result<Option<T::Native>, ArrowError>
581where
582 T: ArrowNumericType,
583 T::Native: ArrowNativeTypeOp,
584{
585 match array.data_type() {
586 DataType::Dictionary(_, _) => {
587 let null_count = array.null_count();
588
589 if null_count == array.len() {
590 return Ok(None);
591 }
592
593 let iter = ArrayIter::new(array);
594 let sum = iter
595 .into_iter()
596 .try_fold(T::default_value(), |accumulator, value| {
597 if let Some(value) = value {
598 accumulator.add_checked(value)
599 } else {
600 Ok(accumulator)
601 }
602 })?;
603
604 Ok(Some(sum))
605 }
606 _ => sum_checked::<T>(as_primitive_array(&array)),
607 }
608}
609
610pub fn min_array<T, A: ArrayAccessor<Item = T::Native>>(array: A) -> Option<T::Native>
613where
614 T: ArrowNumericType,
615 T::Native: ArrowNativeType,
616{
617 min_max_array_helper::<T, A, _, _>(array, |a, b| a.is_gt(*b), min)
618}
619
620pub fn max_array<T, A: ArrayAccessor<Item = T::Native>>(array: A) -> Option<T::Native>
623where
624 T: ArrowNumericType,
625 T::Native: ArrowNativeTypeOp,
626{
627 min_max_array_helper::<T, A, _, _>(array, |a, b| a.is_lt(*b), max)
628}
629
630fn min_max_array_helper<T, A: ArrayAccessor<Item = T::Native>, F, M>(
631 array: A,
632 cmp: F,
633 m: M,
634) -> Option<T::Native>
635where
636 T: ArrowNumericType,
637 F: Fn(&T::Native, &T::Native) -> bool,
638 M: Fn(&PrimitiveArray<T>) -> Option<T::Native>,
639{
640 match array.data_type() {
641 DataType::Dictionary(_, _) => min_max_helper::<T::Native, _, _>(array, cmp),
642 _ => m(as_primitive_array(&array)),
643 }
644}
645
646macro_rules! bit_operation {
647 ($NAME:ident, $OP:ident, $NATIVE:ident, $DEFAULT:expr, $DOC:expr) => {
648 #[doc = $DOC]
649 pub fn $NAME<T>(array: &PrimitiveArray<T>) -> Option<T::Native>
652 where
653 T: ArrowNumericType,
654 T::Native: $NATIVE<Output = T::Native> + ArrowNativeTypeOp,
655 {
656 let default;
657 if $DEFAULT == -1 {
658 default = T::Native::ONE.neg_wrapping();
659 } else {
660 default = T::default_value();
661 }
662
663 let null_count = array.null_count();
664
665 if null_count == array.len() {
666 return None;
667 }
668
669 let data: &[T::Native] = array.values();
670
671 match array.nulls() {
672 None => {
673 let result = data
674 .iter()
675 .fold(default, |accumulator, value| accumulator.$OP(*value));
676
677 Some(result)
678 }
679 Some(nulls) => {
680 let mut result = default;
681 let data_chunks = data.chunks_exact(64);
682 let remainder = data_chunks.remainder();
683
684 let bit_chunks = nulls.inner().bit_chunks();
685 data_chunks
686 .zip(bit_chunks.iter())
687 .for_each(|(chunk, mask)| {
688 let mut index_mask = 1;
690 chunk.iter().for_each(|value| {
691 if (mask & index_mask) != 0 {
692 result = result.$OP(*value);
693 }
694 index_mask <<= 1;
695 });
696 });
697
698 let remainder_bits = bit_chunks.remainder_bits();
699
700 remainder.iter().enumerate().for_each(|(i, value)| {
701 if remainder_bits & (1 << i) != 0 {
702 result = result.$OP(*value);
703 }
704 });
705
706 Some(result)
707 }
708 }
709 }
710 };
711}
712
713bit_operation!(
714 bit_and,
715 bitand,
716 BitAnd,
717 -1,
718 "Returns the bitwise and of all non-null input values."
719);
720bit_operation!(
721 bit_or,
722 bitor,
723 BitOr,
724 0,
725 "Returns the bitwise or of all non-null input values."
726);
727bit_operation!(
728 bit_xor,
729 bitxor,
730 BitXor,
731 0,
732 "Returns the bitwise xor of all non-null input values."
733);
734
735pub fn bool_and(array: &BooleanArray) -> Option<bool> {
739 min_boolean(array)
740}
741
742pub fn bool_or(array: &BooleanArray) -> Option<bool> {
746 max_boolean(array)
747}
748
749pub fn sum_checked<T>(array: &PrimitiveArray<T>) -> Result<Option<T::Native>, ArrowError>
756where
757 T: ArrowNumericType,
758 T::Native: ArrowNativeTypeOp,
759{
760 let null_count = array.null_count();
761
762 if null_count == array.len() {
763 return Ok(None);
764 }
765
766 let data: &[T::Native] = array.values();
767
768 match array.nulls() {
769 None => {
770 let sum = data
771 .iter()
772 .try_fold(T::default_value(), |accumulator, value| {
773 accumulator.add_checked(*value)
774 })?;
775
776 Ok(Some(sum))
777 }
778 Some(nulls) => {
779 let mut sum = T::default_value();
780
781 try_for_each_valid_idx(
782 nulls.len(),
783 nulls.offset(),
784 nulls.null_count(),
785 Some(nulls.validity()),
786 |idx| {
787 unsafe { sum = sum.add_checked(array.value_unchecked(idx))? };
788 Ok::<_, ArrowError>(())
789 },
790 )?;
791
792 Ok(Some(sum))
793 }
794 }
795}
796
797pub fn sum<T: ArrowNumericType>(array: &PrimitiveArray<T>) -> Option<T::Native>
804where
805 T::Native: ArrowNativeTypeOp,
806{
807 aggregate::<T::Native, T, SumAccumulator<T::Native>>(array)
808}
809
810pub fn min<T: ArrowNumericType>(array: &PrimitiveArray<T>) -> Option<T::Native>
813where
814 T::Native: PartialOrd,
815{
816 aggregate::<T::Native, T, MinAccumulator<T::Native>>(array)
817}
818
819pub fn max<T: ArrowNumericType>(array: &PrimitiveArray<T>) -> Option<T::Native>
822where
823 T::Native: PartialOrd,
824{
825 aggregate::<T::Native, T, MaxAccumulator<T::Native>>(array)
826}
827
828#[cfg(test)]
829mod tests {
830 use super::*;
831 use arrow_array::types::*;
832 use builder::BooleanBuilder;
833 use std::sync::Arc;
834
835 #[test]
836 fn test_primitive_array_sum() {
837 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
838 assert_eq!(15, sum(&a).unwrap());
839 }
840
841 #[test]
842 fn test_primitive_array_float_sum() {
843 let a = Float64Array::from(vec![1.1, 2.2, 3.3, 4.4, 5.5]);
844 assert_eq!(16.5, sum(&a).unwrap());
845 }
846
847 #[test]
848 fn test_primitive_array_sum_with_nulls() {
849 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
850 assert_eq!(10, sum(&a).unwrap());
851 }
852
853 #[test]
854 fn test_primitive_array_sum_all_nulls() {
855 let a = Int32Array::from(vec![None, None, None]);
856 assert_eq!(None, sum(&a));
857 }
858
859 #[test]
860 fn test_primitive_array_sum_large_float_64() {
861 let c = Float64Array::new((1..=100).map(|x| x as f64).collect(), None);
862 assert_eq!(Some((1..=100).sum::<i64>() as f64), sum(&c));
863
864 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
866 let c = Float64Array::new((1..=100).map(|x| x as f64).collect(), Some(validity));
867
868 assert_eq!(
869 Some((1..=100).filter(|i| i % 3 == 0).sum::<i64>() as f64),
870 sum(&c)
871 );
872 }
873
874 #[test]
875 fn test_primitive_array_sum_large_float_32() {
876 let c = Float32Array::new((1..=100).map(|x| x as f32).collect(), None);
877 assert_eq!(Some((1..=100).sum::<i64>() as f32), sum(&c));
878
879 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
881 let c = Float32Array::new((1..=100).map(|x| x as f32).collect(), Some(validity));
882
883 assert_eq!(
884 Some((1..=100).filter(|i| i % 3 == 0).sum::<i64>() as f32),
885 sum(&c)
886 );
887 }
888
889 #[test]
890 fn test_primitive_array_sum_large_64() {
891 let c = Int64Array::new((1..=100).collect(), None);
892 assert_eq!(Some((1..=100).sum()), sum(&c));
893
894 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
896 let c = Int64Array::new((1..=100).collect(), Some(validity));
897
898 assert_eq!(Some((1..=100).filter(|i| i % 3 == 0).sum()), sum(&c));
899 }
900
901 #[test]
902 fn test_primitive_array_sum_large_32() {
903 let c = Int32Array::new((1..=100).collect(), None);
904 assert_eq!(Some((1..=100).sum()), sum(&c));
905
906 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
908 let c = Int32Array::new((1..=100).collect(), Some(validity));
909 assert_eq!(Some((1..=100).filter(|i| i % 3 == 0).sum()), sum(&c));
910 }
911
912 #[test]
913 fn test_primitive_array_sum_large_16() {
914 let c = Int16Array::new((1..=100).collect(), None);
915 assert_eq!(Some((1..=100).sum()), sum(&c));
916
917 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
919 let c = Int16Array::new((1..=100).collect(), Some(validity));
920 assert_eq!(Some((1..=100).filter(|i| i % 3 == 0).sum()), sum(&c));
921 }
922
923 #[test]
924 fn test_primitive_array_sum_large_8() {
925 let c = UInt8Array::new((1..=100).collect(), None);
926 assert_eq!(
927 Some((1..=100).fold(0_u8, |a, x| a.wrapping_add(x))),
928 sum(&c)
929 );
930
931 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
933 let c = UInt8Array::new((1..=100).collect(), Some(validity));
934 assert_eq!(
935 Some(
936 (1..=100)
937 .filter(|i| i % 3 == 0)
938 .fold(0_u8, |a, x| a.wrapping_add(x))
939 ),
940 sum(&c)
941 );
942 }
943
944 #[test]
945 fn test_primitive_array_bit_and() {
946 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
947 assert_eq!(0, bit_and(&a).unwrap());
948 }
949
950 #[test]
951 fn test_primitive_array_bit_and_with_nulls() {
952 let a = Int32Array::from(vec![None, Some(2), Some(3), None, None]);
953 assert_eq!(2, bit_and(&a).unwrap());
954 }
955
956 #[test]
957 fn test_primitive_array_bit_and_all_nulls() {
958 let a = Int32Array::from(vec![None, None, None]);
959 assert_eq!(None, bit_and(&a));
960 }
961
962 #[test]
963 fn test_primitive_array_bit_or() {
964 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
965 assert_eq!(7, bit_or(&a).unwrap());
966 }
967
968 #[test]
969 fn test_primitive_array_bit_or_with_nulls() {
970 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
971 assert_eq!(7, bit_or(&a).unwrap());
972 }
973
974 #[test]
975 fn test_primitive_array_bit_or_all_nulls() {
976 let a = Int32Array::from(vec![None, None, None]);
977 assert_eq!(None, bit_or(&a));
978 }
979
980 #[test]
981 fn test_primitive_array_bit_xor() {
982 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
983 assert_eq!(1, bit_xor(&a).unwrap());
984 }
985
986 #[test]
987 fn test_primitive_array_bit_xor_with_nulls() {
988 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
989 assert_eq!(4, bit_xor(&a).unwrap());
990 }
991
992 #[test]
993 fn test_primitive_array_bit_xor_all_nulls() {
994 let a = Int32Array::from(vec![None, None, None]);
995 assert_eq!(None, bit_xor(&a));
996 }
997
998 #[test]
999 fn test_primitive_array_bool_and() {
1000 let a = BooleanArray::from(vec![true, false, true, false, true]);
1001 assert!(!bool_and(&a).unwrap());
1002 }
1003
1004 #[test]
1005 fn test_primitive_array_bool_and_with_nulls() {
1006 let a = BooleanArray::from(vec![None, Some(true), Some(true), None, Some(true)]);
1007 assert!(bool_and(&a).unwrap());
1008 }
1009
1010 #[test]
1011 fn test_primitive_array_bool_and_all_nulls() {
1012 let a = BooleanArray::from(vec![None, None, None]);
1013 assert_eq!(None, bool_and(&a));
1014 }
1015
1016 #[test]
1017 fn test_primitive_array_bool_or() {
1018 let a = BooleanArray::from(vec![true, false, true, false, true]);
1019 assert!(bool_or(&a).unwrap());
1020 }
1021
1022 #[test]
1023 fn test_primitive_array_bool_or_with_nulls() {
1024 let a = BooleanArray::from(vec![None, Some(false), Some(false), None, Some(false)]);
1025 assert!(!bool_or(&a).unwrap());
1026 }
1027
1028 #[test]
1029 fn test_primitive_array_bool_or_all_nulls() {
1030 let a = BooleanArray::from(vec![None, None, None]);
1031 assert_eq!(None, bool_or(&a));
1032 }
1033
1034 #[test]
1035 fn test_primitive_array_min_max() {
1036 let a = Int32Array::from(vec![5, 6, 7, 8, 9]);
1037 assert_eq!(5, min(&a).unwrap());
1038 assert_eq!(9, max(&a).unwrap());
1039 }
1040
1041 #[test]
1042 fn test_primitive_array_min_max_with_nulls() {
1043 let a = Int32Array::from(vec![Some(5), None, None, Some(8), Some(9)]);
1044 assert_eq!(5, min(&a).unwrap());
1045 assert_eq!(9, max(&a).unwrap());
1046 }
1047
1048 #[test]
1049 fn test_primitive_min_max_1() {
1050 let a = Int32Array::from(vec![None, None, Some(5), Some(2)]);
1051 assert_eq!(Some(2), min(&a));
1052 assert_eq!(Some(5), max(&a));
1053 }
1054
1055 #[test]
1056 fn test_primitive_min_max_float_large_nonnull_array() {
1057 let a: Float64Array = (0..256).map(|i| Some((i + 1) as f64)).collect();
1058 assert_eq!(Some(1.0), min(&a));
1060 assert_eq!(Some(256.0), max(&a));
1061
1062 let a: Float64Array = (0..255).map(|i| Some((i + 1) as f64)).collect();
1064 assert_eq!(Some(255.0), max(&a));
1065
1066 let a: Float64Array = (0..257).map(|i| Some((i + 1) as f64)).collect();
1068 assert_eq!(Some(257.0), max(&a));
1069 }
1070
1071 #[test]
1072 fn test_primitive_min_max_float_large_nullable_array() {
1073 let a: Float64Array = (0..256)
1074 .map(|i| {
1075 if (i + 1) % 3 == 0 {
1076 None
1077 } else {
1078 Some((i + 1) as f64)
1079 }
1080 })
1081 .collect();
1082 assert_eq!(Some(1.0), min(&a));
1084 assert_eq!(Some(256.0), max(&a));
1085
1086 let a: Float64Array = (0..256)
1087 .map(|i| {
1088 if i == 0 || i == 255 {
1089 None
1090 } else {
1091 Some((i + 1) as f64)
1092 }
1093 })
1094 .collect();
1095 assert_eq!(Some(2.0), min(&a));
1097 assert_eq!(Some(255.0), max(&a));
1098
1099 let a: Float64Array = (0..256)
1100 .map(|i| if i != 100 { None } else { Some((i) as f64) })
1101 .collect();
1102 assert_eq!(Some(100.0), min(&a));
1104 assert_eq!(Some(100.0), max(&a));
1105
1106 let a: Float64Array = (0..255).map(|i| Some((i + 1) as f64)).collect();
1108 assert_eq!(Some(255.0), max(&a));
1109
1110 let a: Float64Array = (0..257).map(|i| Some((i + 1) as f64)).collect();
1112 assert_eq!(Some(257.0), max(&a));
1113 }
1114
1115 #[test]
1116 fn test_primitive_min_max_float_edge_cases() {
1117 let a: Float64Array = (0..100).map(|_| Some(f64::NEG_INFINITY)).collect();
1118 assert_eq!(Some(f64::NEG_INFINITY), min(&a));
1119 assert_eq!(Some(f64::NEG_INFINITY), max(&a));
1120
1121 let a: Float64Array = (0..100).map(|_| Some(f64::MIN)).collect();
1122 assert_eq!(Some(f64::MIN), min(&a));
1123 assert_eq!(Some(f64::MIN), max(&a));
1124
1125 let a: Float64Array = (0..100).map(|_| Some(f64::MAX)).collect();
1126 assert_eq!(Some(f64::MAX), min(&a));
1127 assert_eq!(Some(f64::MAX), max(&a));
1128
1129 let a: Float64Array = (0..100).map(|_| Some(f64::INFINITY)).collect();
1130 assert_eq!(Some(f64::INFINITY), min(&a));
1131 assert_eq!(Some(f64::INFINITY), max(&a));
1132 }
1133
1134 #[test]
1135 fn test_primitive_min_max_float_all_nans_non_null() {
1136 let a: Float64Array = (0..100).map(|_| Some(f64::NAN)).collect();
1137 assert!(max(&a).unwrap().is_nan());
1138 assert!(min(&a).unwrap().is_nan());
1139 }
1140
1141 #[test]
1142 fn test_primitive_min_max_float_negative_nan() {
1143 let a: Float64Array =
1144 Float64Array::from(vec![f64::NEG_INFINITY, f64::NAN, f64::INFINITY, -f64::NAN]);
1145 let max = max(&a).unwrap();
1146 let min = min(&a).unwrap();
1147 assert!(max.is_nan());
1148 assert!(max.is_sign_positive());
1149
1150 assert!(min.is_nan());
1151 assert!(min.is_sign_negative());
1152 }
1153
1154 #[test]
1155 fn test_primitive_min_max_float_first_nan_nonnull() {
1156 let a: Float64Array = (0..100)
1157 .map(|i| {
1158 if i == 0 {
1159 Some(f64::NAN)
1160 } else {
1161 Some(i as f64)
1162 }
1163 })
1164 .collect();
1165 assert_eq!(Some(1.0), min(&a));
1166 assert!(max(&a).unwrap().is_nan());
1167 }
1168
1169 #[test]
1170 fn test_primitive_min_max_float_last_nan_nonnull() {
1171 let a: Float64Array = (0..100)
1172 .map(|i| {
1173 if i == 99 {
1174 Some(f64::NAN)
1175 } else {
1176 Some((i + 1) as f64)
1177 }
1178 })
1179 .collect();
1180 assert_eq!(Some(1.0), min(&a));
1181 assert!(max(&a).unwrap().is_nan());
1182 }
1183
1184 #[test]
1185 fn test_primitive_min_max_float_first_nan_nullable() {
1186 let a: Float64Array = (0..100)
1187 .map(|i| {
1188 if i == 0 {
1189 Some(f64::NAN)
1190 } else if i % 2 == 0 {
1191 None
1192 } else {
1193 Some(i as f64)
1194 }
1195 })
1196 .collect();
1197 assert_eq!(Some(1.0), min(&a));
1198 assert!(max(&a).unwrap().is_nan());
1199 }
1200
1201 #[test]
1202 fn test_primitive_min_max_float_last_nan_nullable() {
1203 let a: Float64Array = (0..100)
1204 .map(|i| {
1205 if i == 99 {
1206 Some(f64::NAN)
1207 } else if i % 2 == 0 {
1208 None
1209 } else {
1210 Some(i as f64)
1211 }
1212 })
1213 .collect();
1214 assert_eq!(Some(1.0), min(&a));
1215 assert!(max(&a).unwrap().is_nan());
1216 }
1217
1218 #[test]
1219 fn test_primitive_min_max_float_inf_and_nans() {
1220 let a: Float64Array = (0..100)
1221 .map(|i| {
1222 let x = match i % 10 {
1223 0 => f64::NEG_INFINITY,
1224 1 => f64::MIN,
1225 2 => f64::MAX,
1226 4 => f64::INFINITY,
1227 5 => f64::NAN,
1228 _ => i as f64,
1229 };
1230 Some(x)
1231 })
1232 .collect();
1233 assert_eq!(Some(f64::NEG_INFINITY), min(&a));
1234 assert!(max(&a).unwrap().is_nan());
1235 }
1236
1237 fn pad_inputs_and_test_fixed_size_binary(
1238 input: Vec<Option<&[u8]>>,
1239 expected_min: Option<&[u8]>,
1240 expected_max: Option<&[u8]>,
1241 ) {
1242 fn pad_slice(slice: &[u8], len: usize) -> Vec<u8> {
1243 let mut padded = vec![0; len];
1244 padded[..slice.len()].copy_from_slice(slice);
1245 padded
1246 }
1247
1248 let max_len = input
1249 .iter()
1250 .filter_map(|x| x.as_ref().map(|b| b.len()))
1251 .max()
1252 .unwrap_or(0);
1253 let padded_input = input
1254 .iter()
1255 .map(|x| x.as_ref().map(|b| pad_slice(b, max_len)));
1256 let input_arr =
1257 FixedSizeBinaryArray::try_from_sparse_iter_with_size(padded_input, max_len as i32)
1258 .unwrap();
1259 let padded_expected_min = expected_min.map(|b| pad_slice(b, max_len));
1260 let padded_expected_max = expected_max.map(|b| pad_slice(b, max_len));
1261
1262 assert_eq!(
1263 padded_expected_min.as_deref(),
1264 min_fixed_size_binary(&input_arr)
1265 );
1266 assert_eq!(
1267 padded_expected_max.as_deref(),
1268 max_fixed_size_binary(&input_arr)
1269 );
1270 }
1271
1272 macro_rules! test_binary {
1273 ($NAME:ident, $ARRAY:expr, $EXPECTED_MIN:expr, $EXPECTED_MAX: expr) => {
1274 #[test]
1275 fn $NAME() {
1276 let binary = BinaryArray::from($ARRAY);
1277 assert_eq!($EXPECTED_MIN, min_binary(&binary));
1278 assert_eq!($EXPECTED_MAX, max_binary(&binary));
1279
1280 let large_binary = LargeBinaryArray::from($ARRAY);
1281 assert_eq!($EXPECTED_MIN, min_binary(&large_binary));
1282 assert_eq!($EXPECTED_MAX, max_binary(&large_binary));
1283
1284 let binary_view = BinaryViewArray::from($ARRAY);
1285 assert_eq!($EXPECTED_MIN, min_binary_view(&binary_view));
1286 assert_eq!($EXPECTED_MAX, max_binary_view(&binary_view));
1287
1288 pad_inputs_and_test_fixed_size_binary($ARRAY, $EXPECTED_MIN, $EXPECTED_MAX);
1289 }
1290 };
1291 }
1292
1293 test_binary!(
1294 test_binary_min_max_with_nulls,
1295 vec![
1296 Some("b01234567890123".as_bytes()), None,
1298 None,
1299 Some(b"a"),
1300 Some(b"c"),
1301 Some(b"abcdedfg0123456"),
1302 ],
1303 Some("a".as_bytes()),
1304 Some("c".as_bytes())
1305 );
1306
1307 test_binary!(
1308 test_binary_min_max_no_null,
1309 vec![
1310 Some("b".as_bytes()),
1311 Some(b"abcdefghijklmnopqrst"), Some(b"c"),
1313 Some(b"b01234567890123"), ],
1315 Some("abcdefghijklmnopqrst".as_bytes()),
1316 Some("c".as_bytes())
1317 );
1318
1319 test_binary!(test_binary_min_max_all_nulls, vec![None, None], None, None);
1320
1321 test_binary!(
1322 test_binary_min_max_1,
1323 vec![
1324 None,
1325 Some("b01234567890123435".as_bytes()), None,
1327 Some(b"b0123xxxxxxxxxxx"),
1328 Some(b"a")
1329 ],
1330 Some("a".as_bytes()),
1331 Some("b0123xxxxxxxxxxx".as_bytes())
1332 );
1333
1334 macro_rules! test_string {
1335 ($NAME:ident, $ARRAY:expr, $EXPECTED_MIN:expr, $EXPECTED_MAX: expr) => {
1336 #[test]
1337 fn $NAME() {
1338 let string = StringArray::from($ARRAY);
1339 assert_eq!($EXPECTED_MIN, min_string(&string));
1340 assert_eq!($EXPECTED_MAX, max_string(&string));
1341
1342 let large_string = LargeStringArray::from($ARRAY);
1343 assert_eq!($EXPECTED_MIN, min_string(&large_string));
1344 assert_eq!($EXPECTED_MAX, max_string(&large_string));
1345
1346 let string_view = StringViewArray::from($ARRAY);
1347 assert_eq!($EXPECTED_MIN, min_string_view(&string_view));
1348 assert_eq!($EXPECTED_MAX, max_string_view(&string_view));
1349 }
1350 };
1351 }
1352
1353 test_string!(
1354 test_string_min_max_with_nulls,
1355 vec![
1356 Some("b012345678901234"), None,
1358 None,
1359 Some("a"),
1360 Some("c"),
1361 Some("b0123xxxxxxxxxxx")
1362 ],
1363 Some("a"),
1364 Some("c")
1365 );
1366
1367 test_string!(
1368 test_string_min_max_no_null,
1369 vec![
1370 Some("b"),
1371 Some("b012345678901234"), Some("a"),
1373 Some("b012xxxxxxxxxxxx")
1374 ],
1375 Some("a"),
1376 Some("b012xxxxxxxxxxxx")
1377 );
1378
1379 test_string!(
1380 test_string_min_max_all_nulls,
1381 Vec::<Option<&str>>::from_iter([None, None]),
1382 None,
1383 None
1384 );
1385
1386 test_string!(
1387 test_string_min_max_1,
1388 vec![
1389 None,
1390 Some("c12345678901234"), None,
1392 Some("b"),
1393 Some("c1234xxxxxxxxxx")
1394 ],
1395 Some("b"),
1396 Some("c1234xxxxxxxxxx")
1397 );
1398
1399 test_string!(
1400 test_string_min_max_empty,
1401 Vec::<Option<&str>>::new(),
1402 None,
1403 None
1404 );
1405
1406 #[test]
1407 fn test_boolean_min_max_empty() {
1408 let a = BooleanArray::from(vec![] as Vec<Option<bool>>);
1409 assert_eq!(None, min_boolean(&a));
1410 assert_eq!(None, max_boolean(&a));
1411 }
1412
1413 #[test]
1414 fn test_boolean_min_max_all_null() {
1415 let a = BooleanArray::from(vec![None, None]);
1416 assert_eq!(None, min_boolean(&a));
1417 assert_eq!(None, max_boolean(&a));
1418 }
1419
1420 #[test]
1421 fn test_boolean_min_max_no_null() {
1422 let a = BooleanArray::from(vec![Some(true), Some(false), Some(true)]);
1423 assert_eq!(Some(false), min_boolean(&a));
1424 assert_eq!(Some(true), max_boolean(&a));
1425 }
1426
1427 #[test]
1428 fn test_boolean_min_max() {
1429 let a = BooleanArray::from(vec![Some(true), Some(true), None, Some(false), None]);
1430 assert_eq!(Some(false), min_boolean(&a));
1431 assert_eq!(Some(true), max_boolean(&a));
1432
1433 let a = BooleanArray::from(vec![None, Some(true), None, Some(false), None]);
1434 assert_eq!(Some(false), min_boolean(&a));
1435 assert_eq!(Some(true), max_boolean(&a));
1436
1437 let a = BooleanArray::from(vec![Some(false), Some(true), None, Some(false), None]);
1438 assert_eq!(Some(false), min_boolean(&a));
1439 assert_eq!(Some(true), max_boolean(&a));
1440
1441 let a = BooleanArray::from(vec![Some(true), None]);
1442 assert_eq!(Some(true), min_boolean(&a));
1443 assert_eq!(Some(true), max_boolean(&a));
1444
1445 let a = BooleanArray::from(vec![Some(false), None]);
1446 assert_eq!(Some(false), min_boolean(&a));
1447 assert_eq!(Some(false), max_boolean(&a));
1448
1449 let a = BooleanArray::from(vec![Some(true)]);
1450 assert_eq!(Some(true), min_boolean(&a));
1451 assert_eq!(Some(true), max_boolean(&a));
1452
1453 let a = BooleanArray::from(vec![Some(false)]);
1454 assert_eq!(Some(false), min_boolean(&a));
1455 assert_eq!(Some(false), max_boolean(&a));
1456 }
1457
1458 #[test]
1459 fn test_boolean_min_max_smaller() {
1460 let a = BooleanArray::from(vec![Some(false)]);
1461 assert_eq!(Some(false), min_boolean(&a));
1462 assert_eq!(Some(false), max_boolean(&a));
1463
1464 let a = BooleanArray::from(vec![None, Some(false)]);
1465 assert_eq!(Some(false), min_boolean(&a));
1466 assert_eq!(Some(false), max_boolean(&a));
1467
1468 let a = BooleanArray::from(vec![None, Some(true)]);
1469 assert_eq!(Some(true), min_boolean(&a));
1470 assert_eq!(Some(true), max_boolean(&a));
1471
1472 let a = BooleanArray::from(vec![Some(true)]);
1473 assert_eq!(Some(true), min_boolean(&a));
1474 assert_eq!(Some(true), max_boolean(&a));
1475 }
1476
1477 #[test]
1478 fn test_boolean_min_max_64_true_64_false() {
1479 let mut no_nulls = BooleanBuilder::new();
1480 no_nulls.append_slice(&[true; 64]);
1481 no_nulls.append_slice(&[false; 64]);
1482 let no_nulls = no_nulls.finish();
1483
1484 assert_eq!(Some(false), min_boolean(&no_nulls));
1485 assert_eq!(Some(true), max_boolean(&no_nulls));
1486
1487 let mut with_nulls = BooleanBuilder::new();
1488 with_nulls.append_slice(&[true; 31]);
1489 with_nulls.append_null();
1490 with_nulls.append_slice(&[true; 32]);
1491 with_nulls.append_slice(&[false; 1]);
1492 with_nulls.append_nulls(63);
1493 let with_nulls = with_nulls.finish();
1494
1495 assert_eq!(Some(false), min_boolean(&with_nulls));
1496 assert_eq!(Some(true), max_boolean(&with_nulls));
1497 }
1498
1499 #[test]
1500 fn test_boolean_min_max_64_false_64_true() {
1501 let mut no_nulls = BooleanBuilder::new();
1502 no_nulls.append_slice(&[false; 64]);
1503 no_nulls.append_slice(&[true; 64]);
1504 let no_nulls = no_nulls.finish();
1505
1506 assert_eq!(Some(false), min_boolean(&no_nulls));
1507 assert_eq!(Some(true), max_boolean(&no_nulls));
1508
1509 let mut with_nulls = BooleanBuilder::new();
1510 with_nulls.append_slice(&[false; 31]);
1511 with_nulls.append_null();
1512 with_nulls.append_slice(&[false; 32]);
1513 with_nulls.append_slice(&[true; 1]);
1514 with_nulls.append_nulls(63);
1515 let with_nulls = with_nulls.finish();
1516
1517 assert_eq!(Some(false), min_boolean(&with_nulls));
1518 assert_eq!(Some(true), max_boolean(&with_nulls));
1519 }
1520
1521 #[test]
1522 fn test_boolean_min_max_96_true() {
1523 let mut no_nulls = BooleanBuilder::new();
1524 no_nulls.append_slice(&[true; 96]);
1525 let no_nulls = no_nulls.finish();
1526
1527 assert_eq!(Some(true), min_boolean(&no_nulls));
1528 assert_eq!(Some(true), max_boolean(&no_nulls));
1529
1530 let mut with_nulls = BooleanBuilder::new();
1531 with_nulls.append_slice(&[true; 31]);
1532 with_nulls.append_null();
1533 with_nulls.append_slice(&[true; 32]);
1534 with_nulls.append_slice(&[true; 31]);
1535 with_nulls.append_null();
1536 let with_nulls = with_nulls.finish();
1537
1538 assert_eq!(Some(true), min_boolean(&with_nulls));
1539 assert_eq!(Some(true), max_boolean(&with_nulls));
1540 }
1541
1542 #[test]
1543 fn test_boolean_min_max_96_false() {
1544 let mut no_nulls = BooleanBuilder::new();
1545 no_nulls.append_slice(&[false; 96]);
1546 let no_nulls = no_nulls.finish();
1547
1548 assert_eq!(Some(false), min_boolean(&no_nulls));
1549 assert_eq!(Some(false), max_boolean(&no_nulls));
1550
1551 let mut with_nulls = BooleanBuilder::new();
1552 with_nulls.append_slice(&[false; 31]);
1553 with_nulls.append_null();
1554 with_nulls.append_slice(&[false; 32]);
1555 with_nulls.append_slice(&[false; 31]);
1556 with_nulls.append_null();
1557 let with_nulls = with_nulls.finish();
1558
1559 assert_eq!(Some(false), min_boolean(&with_nulls));
1560 assert_eq!(Some(false), max_boolean(&with_nulls));
1561 }
1562
1563 #[test]
1564 fn test_sum_dyn() {
1565 let values = Int8Array::from_iter_values([10_i8, 11, 12, 13, 14, 15, 16, 17]);
1566 let values = Arc::new(values) as ArrayRef;
1567 let keys = Int8Array::from_iter_values([2_i8, 3, 4]);
1568
1569 let dict_array = DictionaryArray::new(keys, values.clone());
1570 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1571 assert_eq!(39, sum_array::<Int8Type, _>(array).unwrap());
1572
1573 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1574 assert_eq!(15, sum_array::<Int32Type, _>(&a).unwrap());
1575
1576 let keys = Int8Array::from(vec![Some(2_i8), None, Some(4)]);
1577 let dict_array = DictionaryArray::new(keys, values.clone());
1578 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1579 assert_eq!(26, sum_array::<Int8Type, _>(array).unwrap());
1580
1581 let keys = Int8Array::from(vec![None, None, None]);
1582 let dict_array = DictionaryArray::new(keys, values.clone());
1583 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1584 assert!(sum_array::<Int8Type, _>(array).is_none());
1585 }
1586
1587 #[test]
1588 fn test_max_min_dyn() {
1589 let values = Int8Array::from_iter_values([10_i8, 11, 12, 13, 14, 15, 16, 17]);
1590 let keys = Int8Array::from_iter_values([2_i8, 3, 4]);
1591 let values = Arc::new(values) as ArrayRef;
1592
1593 let dict_array = DictionaryArray::new(keys, values.clone());
1594 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1595 assert_eq!(14, max_array::<Int8Type, _>(array).unwrap());
1596
1597 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1598 assert_eq!(12, min_array::<Int8Type, _>(array).unwrap());
1599
1600 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1601 assert_eq!(5, max_array::<Int32Type, _>(&a).unwrap());
1602 assert_eq!(1, min_array::<Int32Type, _>(&a).unwrap());
1603
1604 let keys = Int8Array::from(vec![Some(2_i8), None, Some(7)]);
1605 let dict_array = DictionaryArray::new(keys, values.clone());
1606 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1607 assert_eq!(17, max_array::<Int8Type, _>(array).unwrap());
1608 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1609 assert_eq!(12, min_array::<Int8Type, _>(array).unwrap());
1610
1611 let keys = Int8Array::from(vec![None, None, None]);
1612 let dict_array = DictionaryArray::new(keys, values.clone());
1613 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1614 assert!(max_array::<Int8Type, _>(array).is_none());
1615 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1616 assert!(min_array::<Int8Type, _>(array).is_none());
1617 }
1618
1619 #[test]
1620 fn test_max_min_dyn_nan() {
1621 let values = Float32Array::from(vec![5.0_f32, 2.0_f32, f32::NAN]);
1622 let keys = Int8Array::from_iter_values([0_i8, 1, 2]);
1623
1624 let dict_array = DictionaryArray::new(keys, Arc::new(values));
1625 let array = dict_array.downcast_dict::<Float32Array>().unwrap();
1626 assert!(max_array::<Float32Type, _>(array).unwrap().is_nan());
1627
1628 let array = dict_array.downcast_dict::<Float32Array>().unwrap();
1629 assert_eq!(2.0_f32, min_array::<Float32Type, _>(array).unwrap());
1630 }
1631
1632 #[test]
1633 fn test_min_max_sliced_primitive() {
1634 let expected = Some(4.0);
1635 let input: Float64Array = vec![None, Some(4.0)].into_iter().collect();
1636 let actual = min(&input);
1637 assert_eq!(actual, expected);
1638 let actual = max(&input);
1639 assert_eq!(actual, expected);
1640
1641 let sliced_input: Float64Array = vec![None, None, None, None, None, Some(4.0)]
1642 .into_iter()
1643 .collect();
1644 let sliced_input = sliced_input.slice(4, 2);
1645
1646 assert_eq!(&sliced_input, &input);
1647
1648 let actual = min(&sliced_input);
1649 assert_eq!(actual, expected);
1650 let actual = max(&sliced_input);
1651 assert_eq!(actual, expected);
1652 }
1653
1654 #[test]
1655 fn test_min_max_sliced_boolean() {
1656 let expected = Some(true);
1657 let input: BooleanArray = vec![None, Some(true)].into_iter().collect();
1658 let actual = min_boolean(&input);
1659 assert_eq!(actual, expected);
1660 let actual = max_boolean(&input);
1661 assert_eq!(actual, expected);
1662
1663 let sliced_input: BooleanArray = vec![None, None, None, None, None, Some(true)]
1664 .into_iter()
1665 .collect();
1666 let sliced_input = sliced_input.slice(4, 2);
1667
1668 assert_eq!(sliced_input, input);
1669
1670 let actual = min_boolean(&sliced_input);
1671 assert_eq!(actual, expected);
1672 let actual = max_boolean(&sliced_input);
1673 assert_eq!(actual, expected);
1674 }
1675
1676 #[test]
1677 fn test_min_max_sliced_string() {
1678 let expected = Some("foo");
1679 let input: StringArray = vec![None, Some("foo")].into_iter().collect();
1680 let actual = min_string(&input);
1681 assert_eq!(actual, expected);
1682 let actual = max_string(&input);
1683 assert_eq!(actual, expected);
1684
1685 let sliced_input: StringArray = vec![None, None, None, None, None, Some("foo")]
1686 .into_iter()
1687 .collect();
1688 let sliced_input = sliced_input.slice(4, 2);
1689
1690 assert_eq!(&sliced_input, &input);
1691
1692 let actual = min_string(&sliced_input);
1693 assert_eq!(actual, expected);
1694 let actual = max_string(&sliced_input);
1695 assert_eq!(actual, expected);
1696 }
1697
1698 #[test]
1699 fn test_min_max_sliced_binary() {
1700 let expected: Option<&[u8]> = Some(&[5]);
1701 let input: BinaryArray = vec![None, Some(&[5])].into_iter().collect();
1702 let actual = min_binary(&input);
1703 assert_eq!(actual, expected);
1704 let actual = max_binary(&input);
1705 assert_eq!(actual, expected);
1706
1707 let sliced_input: BinaryArray = vec![None, None, None, None, None, Some(&[5])]
1708 .into_iter()
1709 .collect();
1710 let sliced_input = sliced_input.slice(4, 2);
1711
1712 assert_eq!(&sliced_input, &input);
1713
1714 let actual = min_binary(&sliced_input);
1715 assert_eq!(actual, expected);
1716 let actual = max_binary(&sliced_input);
1717 assert_eq!(actual, expected);
1718 }
1719
1720 #[test]
1721 fn test_sum_overflow() {
1722 let a = Int32Array::from(vec![i32::MAX, 1]);
1723
1724 assert_eq!(sum(&a).unwrap(), -2147483648);
1725 assert_eq!(sum_array::<Int32Type, _>(&a).unwrap(), -2147483648);
1726 }
1727
1728 #[test]
1729 fn test_sum_checked_overflow() {
1730 let a = Int32Array::from(vec![i32::MAX, 1]);
1731
1732 sum_checked(&a).expect_err("overflow should be detected");
1733 sum_array_checked::<Int32Type, _>(&a).expect_err("overflow should be detected");
1734 }
1735}