1use arrow_array::cast::*;
21use arrow_array::iterator::ArrayIter;
22use arrow_array::*;
23use arrow_buffer::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 ProductAccumulator<T: ArrowNativeTypeOp> {
83 product: T,
84}
85
86impl<T: ArrowNativeTypeOp> Default for ProductAccumulator<T> {
87 fn default() -> Self {
88 Self { product: T::ONE }
89 }
90}
91
92impl<T: ArrowNativeTypeOp> NumericAccumulator<T> for ProductAccumulator<T> {
93 fn accumulate(&mut self, value: T) {
94 self.product = self.product.mul_wrapping(value);
95 }
96
97 fn accumulate_nullable(&mut self, value: T, valid: bool) {
98 let product = self.product;
99 self.product = select(valid, product.mul_wrapping(value), product)
100 }
101
102 fn merge(&mut self, other: Self) {
103 self.product = self.product.mul_wrapping(other.product);
104 }
105
106 fn finish(&mut self) -> T {
107 self.product
108 }
109}
110
111#[derive(Clone, Copy)]
112struct MinAccumulator<T: ArrowNativeTypeOp> {
113 min: T,
114}
115
116impl<T: ArrowNativeTypeOp> Default for MinAccumulator<T> {
117 fn default() -> Self {
118 Self {
119 min: T::MAX_TOTAL_ORDER,
120 }
121 }
122}
123
124impl<T: ArrowNativeTypeOp> NumericAccumulator<T> for MinAccumulator<T> {
125 fn accumulate(&mut self, value: T) {
126 let min = self.min;
127 self.min = select(value.is_lt(min), value, min);
128 }
129
130 fn accumulate_nullable(&mut self, value: T, valid: bool) {
131 let min = self.min;
132 let is_lt = valid & value.is_lt(min);
133 self.min = select(is_lt, value, min);
134 }
135
136 fn merge(&mut self, other: Self) {
137 self.accumulate(other.min)
138 }
139
140 fn finish(&mut self) -> T {
141 self.min
142 }
143}
144
145#[derive(Clone, Copy)]
146struct MaxAccumulator<T: ArrowNativeTypeOp> {
147 max: T,
148}
149
150impl<T: ArrowNativeTypeOp> Default for MaxAccumulator<T> {
151 fn default() -> Self {
152 Self {
153 max: T::MIN_TOTAL_ORDER,
154 }
155 }
156}
157
158impl<T: ArrowNativeTypeOp> NumericAccumulator<T> for MaxAccumulator<T> {
159 fn accumulate(&mut self, value: T) {
160 let max = self.max;
161 self.max = select(value.is_gt(max), value, max);
162 }
163
164 fn accumulate_nullable(&mut self, value: T, valid: bool) {
165 let max = self.max;
166 let is_gt = value.is_gt(max) & valid;
167 self.max = select(is_gt, value, max);
168 }
169
170 fn merge(&mut self, other: Self) {
171 self.accumulate(other.max)
172 }
173
174 fn finish(&mut self) -> T {
175 self.max
176 }
177}
178
179fn reduce_accumulators<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
180 mut acc: [A; LANES],
181) -> A {
182 assert!(LANES > 0 && LANES.is_power_of_two());
183 let mut len = LANES;
184
185 while len >= 2 {
188 let mid = len / 2;
189 let (h, t) = acc[..len].split_at_mut(mid);
190
191 for i in 0..mid {
192 h[i].merge(t[i]);
193 }
194 len /= 2;
195 }
196 acc[0]
197}
198
199#[inline(always)]
200fn aggregate_nonnull_chunk<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
201 acc: &mut [A; LANES],
202 values: &[T; LANES],
203) {
204 for i in 0..LANES {
205 acc[i].accumulate(values[i]);
206 }
207}
208
209#[inline(always)]
210fn aggregate_nullable_chunk<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
211 acc: &mut [A; LANES],
212 values: &[T; LANES],
213 validity: u64,
214) {
215 let mut bit = 1;
216 for i in 0..LANES {
217 acc[i].accumulate_nullable(values[i], (validity & bit) != 0);
218 bit <<= 1;
219 }
220}
221
222fn aggregate_nonnull_simple<T: ArrowNativeTypeOp, A: NumericAccumulator<T>>(values: &[T]) -> T {
223 values
224 .iter()
225 .copied()
226 .fold(A::default(), |mut a, b| {
227 a.accumulate(b);
228 a
229 })
230 .finish()
231}
232
233#[inline(never)]
234fn aggregate_nonnull_lanes<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
235 values: &[T],
236) -> T {
237 let mut acc = [A::default(); LANES];
240 let mut chunks = values.chunks_exact(LANES);
241 chunks.borrow_mut().for_each(|chunk| {
242 aggregate_nonnull_chunk(&mut acc, chunk[..LANES].try_into().unwrap());
243 });
244
245 let remainder = chunks.remainder();
246 for i in 0..remainder.len() {
247 acc[i].accumulate(remainder[i]);
248 }
249
250 reduce_accumulators(acc).finish()
251}
252
253#[inline(never)]
254fn aggregate_nullable_lanes<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
255 values: &[T],
256 validity: &NullBuffer,
257) -> T {
258 assert!(LANES > 0 && 64 % LANES == 0);
259 assert_eq!(values.len(), validity.len());
260
261 let mut acc = [A::default(); LANES];
263 let mut values_chunks = values.chunks_exact(64);
265 let validity_chunks = validity.inner().bit_chunks();
266 let mut validity_chunks_iter = validity_chunks.iter();
267
268 values_chunks.borrow_mut().for_each(|chunk| {
269 let mut validity = unsafe { validity_chunks_iter.next().unwrap_unchecked() };
271 chunk.chunks_exact(LANES).for_each(|chunk| {
273 aggregate_nullable_chunk(&mut acc, chunk[..LANES].try_into().unwrap(), validity);
274 validity >>= LANES;
275 });
276 });
277
278 let remainder = values_chunks.remainder();
279 if !remainder.is_empty() {
280 let mut validity = validity_chunks.remainder_bits();
281
282 let mut remainder_chunks = remainder.chunks_exact(LANES);
283 remainder_chunks.borrow_mut().for_each(|chunk| {
284 aggregate_nullable_chunk(&mut acc, chunk[..LANES].try_into().unwrap(), validity);
285 validity >>= LANES;
286 });
287
288 let remainder = remainder_chunks.remainder();
289 if !remainder.is_empty() {
290 let mut bit = 1;
291 for i in 0..remainder.len() {
292 acc[i].accumulate_nullable(remainder[i], (validity & bit) != 0);
293 bit <<= 1;
294 }
295 }
296 }
297
298 reduce_accumulators(acc).finish()
299}
300
301const PREFERRED_VECTOR_SIZE: usize =
304 if cfg!(all(target_arch = "x86_64", target_feature = "avx512f")) {
305 64
306 } else if cfg!(all(target_arch = "x86_64", target_feature = "avx")) {
307 32
308 } else {
309 16
310 };
311
312const PREFERRED_VECTOR_SIZE_NON_NULL: usize = PREFERRED_VECTOR_SIZE * 2;
314
315fn aggregate<T: ArrowNativeTypeOp, P: ArrowPrimitiveType<Native = T>, A: NumericAccumulator<T>>(
318 array: &PrimitiveArray<P>,
319) -> Option<T> {
320 let null_count = array.null_count();
321 if null_count == array.len() {
322 return None;
323 }
324 let values = array.values().as_ref();
325 match array.nulls() {
326 Some(nulls) if null_count > 0 => {
327 match PREFERRED_VECTOR_SIZE / std::mem::size_of::<T>() {
330 64 => Some(aggregate_nullable_lanes::<T, A, 64>(values, nulls)),
331 32 => Some(aggregate_nullable_lanes::<T, A, 32>(values, nulls)),
332 16 => Some(aggregate_nullable_lanes::<T, A, 16>(values, nulls)),
333 8 => Some(aggregate_nullable_lanes::<T, A, 8>(values, nulls)),
334 4 => Some(aggregate_nullable_lanes::<T, A, 4>(values, nulls)),
335 2 => Some(aggregate_nullable_lanes::<T, A, 2>(values, nulls)),
336 _ => Some(aggregate_nullable_lanes::<T, A, 1>(values, nulls)),
337 }
338 }
339 _ => {
340 let is_float = matches!(
341 array.data_type(),
342 DataType::Float16 | DataType::Float32 | DataType::Float64
343 );
344 if is_float {
345 match PREFERRED_VECTOR_SIZE_NON_NULL / std::mem::size_of::<T>() {
346 64 => Some(aggregate_nonnull_lanes::<T, A, 64>(values)),
347 32 => Some(aggregate_nonnull_lanes::<T, A, 32>(values)),
348 16 => Some(aggregate_nonnull_lanes::<T, A, 16>(values)),
349 8 => Some(aggregate_nonnull_lanes::<T, A, 8>(values)),
350 4 => Some(aggregate_nonnull_lanes::<T, A, 4>(values)),
351 2 => Some(aggregate_nonnull_lanes::<T, A, 2>(values)),
352 _ => Some(aggregate_nonnull_simple::<T, A>(values)),
353 }
354 } else {
355 Some(aggregate_nonnull_simple::<T, A>(values))
358 }
359 }
360 }
361}
362
363pub fn min_boolean(array: &BooleanArray) -> Option<bool> {
373 if array.null_count() == array.len() {
375 return None;
376 }
377
378 match array.nulls() {
380 None => {
381 let bit_chunks = array.values().bit_chunks();
382 if bit_chunks.iter().any(|x| {
383 x != u64::MAX
385 }) {
386 return Some(false);
387 }
388 if bit_chunks.remainder_bits().count_ones() as usize != bit_chunks.remainder_len() {
390 Some(false)
391 } else {
392 Some(true)
393 }
394 }
395 Some(nulls) => {
396 let validity_chunks = nulls.inner().bit_chunks();
397 let value_chunks = array.values().bit_chunks();
398
399 if value_chunks
400 .iter()
401 .zip(validity_chunks.iter())
402 .any(|(value, validity)| {
403 (!value & validity) != 0
406 })
407 {
408 return Some(false);
409 }
410
411 if (!value_chunks.remainder_bits() & validity_chunks.remainder_bits()) != 0 {
413 Some(false)
414 } else {
415 Some(true)
416 }
417 }
418 }
419}
420
421pub fn max_boolean(array: &BooleanArray) -> Option<bool> {
431 if array.null_count() == array.len() {
433 return None;
434 }
435
436 match array.nulls() {
438 None => array
439 .values()
440 .bit_chunks()
441 .iter_padded()
442 .map(|x| x != 0)
444 .find(|b| *b)
445 .or(Some(false)),
446 Some(nulls) => {
447 let validity_chunks = nulls.inner().bit_chunks().iter_padded();
448 let value_chunks = array.values().bit_chunks().iter_padded();
449 value_chunks
450 .zip(validity_chunks)
451 .map(|(value_bits, validity_bits)| (value_bits & validity_bits) != 0)
453 .find(|b| *b)
454 .or(Some(false))
455 }
456 }
457}
458
459fn min_max_helper<T, A: ArrayAccessor<Item = T>, F>(array: A, cmp: F) -> Option<T>
461where
462 F: Fn(&T, &T) -> bool,
463{
464 let null_count = array.null_count();
465 if null_count == array.len() {
466 None
467 } else if null_count == 0 {
468 (0..array.len())
472 .map(|i| unsafe { array.value_unchecked(i) })
473 .reduce(|acc, item| if cmp(&acc, &item) { item } else { acc })
474 } else {
475 let nulls = array.nulls().unwrap();
476 unsafe {
477 let idx = nulls.valid_indices().reduce(|acc_idx, idx| {
478 let acc = array.value_unchecked(acc_idx);
479 let item = array.value_unchecked(idx);
480 if cmp(&acc, &item) { idx } else { acc_idx }
481 });
482 idx.map(|idx| array.value_unchecked(idx))
483 }
484 }
485}
486
487fn min_max_view_helper<T: ByteViewType>(
492 array: &GenericByteViewArray<T>,
493 swap_cond: cmp::Ordering,
494) -> Option<&T::Native> {
495 let null_count = array.null_count();
496 if null_count == array.len() {
497 None
498 } else if null_count == 0 {
499 let target_idx = (0..array.len()).reduce(|acc, item| {
500 let cmp = unsafe { GenericByteViewArray::compare_unchecked(array, item, array, acc) };
502 if cmp == swap_cond { item } else { acc }
503 });
504 unsafe { target_idx.map(|idx| array.value_unchecked(idx)) }
506 } else {
507 let nulls = array.nulls().unwrap();
508
509 let target_idx = nulls.valid_indices().reduce(|acc_idx, idx| {
510 let cmp =
511 unsafe { GenericByteViewArray::compare_unchecked(array, idx, array, acc_idx) };
512 if cmp == swap_cond { idx } else { acc_idx }
513 });
514
515 unsafe { target_idx.map(|idx| array.value_unchecked(idx)) }
517 }
518}
519
520pub fn max_binary<T: OffsetSizeTrait>(array: &GenericBinaryArray<T>) -> Option<&[u8]> {
522 min_max_helper::<&[u8], _, _>(array, |a, b| *a < *b)
523}
524
525pub fn max_binary_view(array: &BinaryViewArray) -> Option<&[u8]> {
527 min_max_view_helper(array, Ordering::Greater)
528}
529
530pub fn max_fixed_size_binary(array: &FixedSizeBinaryArray) -> Option<&[u8]> {
532 min_max_helper::<&[u8], _, _>(array, |a, b| *a < *b)
533}
534
535pub fn min_binary<T: OffsetSizeTrait>(array: &GenericBinaryArray<T>) -> Option<&[u8]> {
537 min_max_helper::<&[u8], _, _>(array, |a, b| *a > *b)
538}
539
540pub fn min_binary_view(array: &BinaryViewArray) -> Option<&[u8]> {
542 min_max_view_helper(array, Ordering::Less)
543}
544
545pub fn min_fixed_size_binary(array: &FixedSizeBinaryArray) -> Option<&[u8]> {
547 min_max_helper::<&[u8], _, _>(array, |a, b| *a > *b)
548}
549
550pub fn max_string<T: OffsetSizeTrait>(array: &GenericStringArray<T>) -> Option<&str> {
552 min_max_helper::<&str, _, _>(array, |a, b| *a < *b)
553}
554
555pub fn max_string_view(array: &StringViewArray) -> Option<&str> {
557 min_max_view_helper(array, Ordering::Greater)
558}
559
560pub fn min_string<T: OffsetSizeTrait>(array: &GenericStringArray<T>) -> Option<&str> {
562 min_max_helper::<&str, _, _>(array, |a, b| *a > *b)
563}
564
565pub fn min_string_view(array: &StringViewArray) -> Option<&str> {
567 min_max_view_helper(array, Ordering::Less)
568}
569
570pub fn sum_array<T: ArrowNumericType, A: ArrayAccessor<Item = T::Native>>(
575 array: A,
576) -> Option<T::Native> {
577 match array.data_type() {
578 DataType::Dictionary(_, _) => {
579 let null_count = array.null_count();
580
581 if null_count == array.len() {
582 return None;
583 }
584
585 let iter = ArrayIter::new(array);
586 let sum = iter
587 .into_iter()
588 .fold(T::default_value(), |accumulator, value| {
589 if let Some(value) = value {
590 accumulator.add_wrapping(value)
591 } else {
592 accumulator
593 }
594 });
595
596 Some(sum)
597 }
598 DataType::RunEndEncoded(run_ends, _) => match run_ends.data_type() {
599 DataType::Int16 => ree::sum_wrapping::<types::Int16Type, T>(&array),
600 DataType::Int32 => ree::sum_wrapping::<types::Int32Type, T>(&array),
601 DataType::Int64 => ree::sum_wrapping::<types::Int64Type, T>(&array),
602 _ => unreachable!(),
603 },
604 _ => sum::<T>(as_primitive_array(&array)),
605 }
606}
607
608pub fn sum_array_checked<T: ArrowNumericType, A: ArrayAccessor<Item = T::Native>>(
615 array: A,
616) -> Result<Option<T::Native>, ArrowError> {
617 match array.data_type() {
618 DataType::Dictionary(_, _) => {
619 let null_count = array.null_count();
620
621 if null_count == array.len() {
622 return Ok(None);
623 }
624
625 let iter = ArrayIter::new(array);
626 let sum = iter
627 .into_iter()
628 .try_fold(T::default_value(), |accumulator, value| {
629 if let Some(value) = value {
630 accumulator.add_checked(value)
631 } else {
632 Ok(accumulator)
633 }
634 })?;
635
636 Ok(Some(sum))
637 }
638 DataType::RunEndEncoded(run_ends, _) => match run_ends.data_type() {
639 DataType::Int16 => ree::sum_checked::<types::Int16Type, T>(&array),
640 DataType::Int32 => ree::sum_checked::<types::Int32Type, T>(&array),
641 DataType::Int64 => ree::sum_checked::<types::Int64Type, T>(&array),
642 _ => unreachable!(),
643 },
644 _ => sum_checked::<T>(as_primitive_array(&array)),
645 }
646}
647
648mod ree {
650 use std::convert::Infallible;
651
652 use arrow_array::cast::AsArray;
653 use arrow_array::types::RunEndIndexType;
654 use arrow_array::{Array, ArrowNativeTypeOp, ArrowNumericType, PrimitiveArray, TypedRunArray};
655 use arrow_buffer::ArrowNativeType;
656 use arrow_schema::ArrowError;
657
658 fn downcast<'a, I: RunEndIndexType, V: ArrowNumericType>(
660 array: &'a dyn Array,
661 ) -> Option<TypedRunArray<'a, I, PrimitiveArray<V>>> {
662 let array = array.as_run_opt::<I>()?;
663 array.downcast::<PrimitiveArray<V>>()
665 }
666
667 pub(super) fn sum_wrapping<I: RunEndIndexType, V: ArrowNumericType>(
669 array: &dyn Array,
670 ) -> Option<V::Native> {
671 let ree = downcast::<I, V>(array)?;
672 let Ok(sum) = fold(ree, |acc, val, len| -> Result<V::Native, Infallible> {
673 Ok(acc.add_wrapping(val.mul_wrapping(V::Native::usize_as(len))))
674 });
675 sum
676 }
677
678 pub(super) fn sum_checked<I: RunEndIndexType, V: ArrowNumericType>(
680 array: &dyn Array,
681 ) -> Result<Option<V::Native>, ArrowError> {
682 let Some(ree) = downcast::<I, V>(array) else {
683 return Err(ArrowError::InvalidArgumentError(
684 "Input run array values are not a PrimitiveArray".to_string(),
685 ));
686 };
687 fold(ree, |acc, val, len| -> Result<V::Native, ArrowError> {
688 let Some(len) = V::Native::from_usize(len) else {
689 return Err(ArrowError::ArithmeticOverflow(format!(
690 "Cannot convert a run-end index ({:?}) to the value type ({})",
691 len,
692 std::any::type_name::<V::Native>()
693 )));
694 };
695 acc.add_checked(val.mul_checked(len)?)
696 })
697 }
698
699 fn fold<'a, I: RunEndIndexType, V: ArrowNumericType, F, E>(
701 array: TypedRunArray<'a, I, PrimitiveArray<V>>,
702 mut f: F,
703 ) -> Result<Option<V::Native>, E>
704 where
705 F: FnMut(V::Native, V::Native, usize) -> Result<V::Native, E>,
706 {
707 let run_ends = array.run_ends();
708 let logical_start = run_ends.offset();
709 let logical_end = run_ends.offset() + run_ends.len();
710 let run_ends = run_ends.sliced_values();
711
712 let values_slice = array.run_array().values_slice();
713 let values = values_slice
714 .as_any()
715 .downcast_ref::<PrimitiveArray<V>>()
716 .unwrap();
718
719 let mut prev_end = 0;
720 let mut acc = V::Native::ZERO;
721 let mut has_non_null_value = false;
722
723 for (run_end, value) in run_ends.zip(values) {
724 let current_run_end = run_end.as_usize().clamp(logical_start, logical_end);
725 let run_length = current_run_end - prev_end;
726
727 if let Some(value) = value {
728 has_non_null_value = true;
729 acc = f(acc, value, run_length)?;
730 }
731
732 prev_end = current_run_end;
733 if current_run_end == logical_end {
734 break;
735 }
736 }
737
738 Ok(if has_non_null_value { Some(acc) } else { None })
739 }
740}
741
742pub fn min_array<T: ArrowNumericType, A: ArrayAccessor<Item = T::Native>>(
745 array: A,
746) -> Option<T::Native> {
747 min_max_array_helper::<T, A, _, _>(array, |a, b| a.is_gt(*b), min)
748}
749
750pub fn max_array<T: ArrowNumericType, A: ArrayAccessor<Item = T::Native>>(
753 array: A,
754) -> Option<T::Native> {
755 min_max_array_helper::<T, A, _, _>(array, |a, b| a.is_lt(*b), max)
756}
757
758fn min_max_array_helper<T, A: ArrayAccessor<Item = T::Native>, F, M>(
759 array: A,
760 cmp: F,
761 m: M,
762) -> Option<T::Native>
763where
764 T: ArrowNumericType,
765 F: Fn(&T::Native, &T::Native) -> bool,
766 M: Fn(&PrimitiveArray<T>) -> Option<T::Native>,
767{
768 match array.data_type() {
769 DataType::Dictionary(_, _) => min_max_helper::<T::Native, _, _>(array, cmp),
770 DataType::RunEndEncoded(run_ends, _) => {
771 let array: &dyn Array = &array;
774 let values = match run_ends.data_type() {
775 DataType::Int16 => array.as_run_opt::<types::Int16Type>()?.values_slice(),
776 DataType::Int32 => array.as_run_opt::<types::Int32Type>()?.values_slice(),
777 DataType::Int64 => array.as_run_opt::<types::Int64Type>()?.values_slice(),
778 _ => return None,
779 };
780 let values = values.as_any().downcast_ref::<PrimitiveArray<T>>()?;
782 m(values)
783 }
784 _ => m(as_primitive_array(&array)),
785 }
786}
787
788macro_rules! bit_operation {
789 ($NAME:ident, $OP:ident, $NATIVE:ident, $DEFAULT:expr, $DOC:expr) => {
790 #[doc = $DOC]
791 pub fn $NAME<T>(array: &PrimitiveArray<T>) -> Option<T::Native>
794 where
795 T: ArrowNumericType,
796 T::Native: $NATIVE<Output = T::Native> + ArrowNativeTypeOp,
797 {
798 let default;
799 if $DEFAULT == -1 {
800 default = T::Native::ONE.neg_wrapping();
801 } else {
802 default = T::default_value();
803 }
804
805 let null_count = array.null_count();
806
807 if null_count == array.len() {
808 return None;
809 }
810
811 let data: &[T::Native] = array.values();
812
813 match array.nulls() {
814 None => {
815 let result = data
816 .iter()
817 .fold(default, |accumulator, value| accumulator.$OP(*value));
818
819 Some(result)
820 }
821 Some(nulls) => {
822 let mut result = default;
823 let data_chunks = data.chunks_exact(64);
824 let remainder = data_chunks.remainder();
825
826 let bit_chunks = nulls.inner().bit_chunks();
827 data_chunks
828 .zip(bit_chunks.iter())
829 .for_each(|(chunk, mask)| {
830 let mut index_mask = 1;
832 chunk.iter().for_each(|value| {
833 if (mask & index_mask) != 0 {
834 result = result.$OP(*value);
835 }
836 index_mask <<= 1;
837 });
838 });
839
840 let remainder_bits = bit_chunks.remainder_bits();
841
842 remainder.iter().enumerate().for_each(|(i, value)| {
843 if remainder_bits & (1 << i) != 0 {
844 result = result.$OP(*value);
845 }
846 });
847
848 Some(result)
849 }
850 }
851 }
852 };
853}
854
855bit_operation!(
856 bit_and,
857 bitand,
858 BitAnd,
859 -1,
860 "Returns the bitwise and of all non-null input values."
861);
862bit_operation!(
863 bit_or,
864 bitor,
865 BitOr,
866 0,
867 "Returns the bitwise or of all non-null input values."
868);
869bit_operation!(
870 bit_xor,
871 bitxor,
872 BitXor,
873 0,
874 "Returns the bitwise xor of all non-null input values."
875);
876
877pub fn bool_and(array: &BooleanArray) -> Option<bool> {
881 min_boolean(array)
882}
883
884pub fn bool_or(array: &BooleanArray) -> Option<bool> {
888 max_boolean(array)
889}
890
891pub fn sum_checked<T: ArrowNumericType>(
898 array: &PrimitiveArray<T>,
899) -> Result<Option<T::Native>, ArrowError> {
900 let null_count = array.null_count();
901
902 if null_count == array.len() {
903 return Ok(None);
904 }
905
906 let data: &[T::Native] = array.values();
907
908 match array.nulls() {
909 None => {
910 let sum = data
911 .iter()
912 .try_fold(T::default_value(), |accumulator, value| {
913 accumulator.add_checked(*value)
914 })?;
915
916 Ok(Some(sum))
917 }
918 Some(nulls) => {
919 let mut sum = T::default_value();
920
921 try_for_each_valid_idx(
922 nulls.len(),
923 nulls.offset(),
924 nulls.null_count(),
925 Some(nulls.validity()),
926 |idx| {
927 unsafe { sum = sum.add_checked(array.value_unchecked(idx))? };
928 Ok::<_, ArrowError>(())
929 },
930 )?;
931
932 Ok(Some(sum))
933 }
934 }
935}
936
937pub fn sum<T: ArrowNumericType>(array: &PrimitiveArray<T>) -> Option<T::Native> {
944 aggregate::<T::Native, T, SumAccumulator<T::Native>>(array)
945}
946
947pub fn product<T: ArrowNumericType>(array: &PrimitiveArray<T>) -> Option<T::Native> {
954 aggregate::<T::Native, T, ProductAccumulator<T::Native>>(array)
955}
956
957pub fn product_checked<T: ArrowNumericType>(
964 array: &PrimitiveArray<T>,
965) -> Result<Option<T::Native>, ArrowError> {
966 let null_count = array.null_count();
967
968 if null_count == array.len() {
969 return Ok(None);
970 }
971
972 let data: &[T::Native] = array.values();
973
974 match array.nulls() {
975 None => {
976 let product = data.iter().try_fold(T::Native::ONE, |accumulator, value| {
977 accumulator.mul_checked(*value)
978 })?;
979
980 Ok(Some(product))
981 }
982 Some(nulls) => {
983 let mut product = T::Native::ONE;
984
985 try_for_each_valid_idx(
986 nulls.len(),
987 nulls.offset(),
988 nulls.null_count(),
989 Some(nulls.validity()),
990 |idx| {
991 unsafe { product = product.mul_checked(array.value_unchecked(idx))? };
992 Ok::<_, ArrowError>(())
993 },
994 )?;
995
996 Ok(Some(product))
997 }
998 }
999}
1000
1001pub fn min<T: ArrowNumericType>(array: &PrimitiveArray<T>) -> Option<T::Native> {
1013 aggregate::<T::Native, T, MinAccumulator<T::Native>>(array)
1014}
1015
1016pub fn max<T: ArrowNumericType>(array: &PrimitiveArray<T>) -> Option<T::Native> {
1028 aggregate::<T::Native, T, MaxAccumulator<T::Native>>(array)
1029}
1030
1031#[cfg(test)]
1032mod tests {
1033 use super::*;
1034 use arrow_array::types::*;
1035 use builder::BooleanBuilder;
1036 use std::sync::Arc;
1037
1038 #[test]
1039 fn test_primitive_array_sum() {
1040 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1041 assert_eq!(15, sum(&a).unwrap());
1042 }
1043
1044 #[test]
1045 fn test_primitive_array_float_sum() {
1046 let a = Float64Array::from(vec![1.1, 2.2, 3.3, 4.4, 5.5]);
1047 assert_eq!(16.5, sum(&a).unwrap());
1048 }
1049
1050 #[test]
1051 fn test_primitive_array_product() {
1052 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1053 assert_eq!(120, product(&a).unwrap());
1054 }
1055
1056 #[test]
1057 fn test_primitive_array_float_product() {
1058 let a = Float64Array::from(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
1059 assert_eq!(120.0, product(&a).unwrap());
1060 }
1061
1062 #[test]
1063 fn test_primitive_array_product_with_nulls() {
1064 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
1065 assert_eq!(30, product(&a).unwrap());
1066 }
1067
1068 #[test]
1069 fn test_primitive_array_product_all_nulls() {
1070 let a = Int32Array::from(vec![None, None, None]);
1071 assert_eq!(None, product(&a));
1072 }
1073
1074 #[test]
1075 fn test_primitive_array_product_empty() {
1076 let a = Int32Array::from(Vec::<i32>::new());
1077 assert_eq!(None, product(&a));
1078 }
1079
1080 #[test]
1081 fn test_primitive_array_product_checked() {
1082 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1083 assert_eq!(120, product_checked(&a).unwrap().unwrap());
1084 }
1085
1086 #[test]
1087 fn test_primitive_array_product_checked_with_nulls() {
1088 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
1089 assert_eq!(30, product_checked(&a).unwrap().unwrap());
1090 }
1091
1092 #[test]
1093 fn test_primitive_array_product_checked_all_nulls() {
1094 let a = Int32Array::from(vec![None, None, None]);
1095 assert_eq!(None, product_checked(&a).unwrap());
1096 }
1097
1098 #[test]
1099 fn test_product_overflow() {
1100 let a = Int32Array::from(vec![i32::MAX, 2]);
1101 assert_eq!(product(&a).unwrap(), -2);
1103 }
1104
1105 #[test]
1106 fn test_product_checked_overflow() {
1107 let a = Int32Array::from(vec![i32::MAX, 2]);
1108 product_checked(&a).expect_err("overflow should be detected");
1109 }
1110
1111 #[test]
1112 fn test_primitive_array_sum_with_nulls() {
1113 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
1114 assert_eq!(10, sum(&a).unwrap());
1115 }
1116
1117 #[test]
1118 fn test_primitive_array_sum_all_nulls() {
1119 let a = Int32Array::from(vec![None, None, None]);
1120 assert_eq!(None, sum(&a));
1121 }
1122
1123 #[test]
1124 fn test_primitive_array_sum_large_float_64() {
1125 let c = Float64Array::new((1..=100).map(|x| x as f64).collect(), None);
1126 assert_eq!(Some((1..=100).sum::<i64>() as f64), sum(&c));
1127
1128 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1130 let c = Float64Array::new((1..=100).map(|x| x as f64).collect(), Some(validity));
1131
1132 assert_eq!(
1133 Some((1..=100).filter(|i| i % 3 == 0).sum::<i64>() as f64),
1134 sum(&c)
1135 );
1136 }
1137
1138 #[test]
1139 fn test_primitive_array_sum_large_float_32() {
1140 let c = Float32Array::new((1..=100).map(|x| x as f32).collect(), None);
1141 assert_eq!(Some((1..=100).sum::<i64>() as f32), sum(&c));
1142
1143 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1145 let c = Float32Array::new((1..=100).map(|x| x as f32).collect(), Some(validity));
1146
1147 assert_eq!(
1148 Some((1..=100).filter(|i| i % 3 == 0).sum::<i64>() as f32),
1149 sum(&c)
1150 );
1151 }
1152
1153 #[test]
1154 fn test_primitive_array_sum_large_64() {
1155 let c = Int64Array::new((1..=100).collect(), None);
1156 assert_eq!(Some((1..=100).sum()), sum(&c));
1157
1158 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1160 let c = Int64Array::new((1..=100).collect(), Some(validity));
1161
1162 assert_eq!(Some((1..=100).filter(|i| i % 3 == 0).sum()), sum(&c));
1163 }
1164
1165 #[test]
1166 fn test_primitive_array_sum_large_32() {
1167 let c = Int32Array::new((1..=100).collect(), None);
1168 assert_eq!(Some((1..=100).sum()), sum(&c));
1169
1170 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1172 let c = Int32Array::new((1..=100).collect(), Some(validity));
1173 assert_eq!(Some((1..=100).filter(|i| i % 3 == 0).sum()), sum(&c));
1174 }
1175
1176 #[test]
1177 fn test_primitive_array_sum_large_16() {
1178 let c = Int16Array::new((1..=100).collect(), None);
1179 assert_eq!(Some((1..=100).sum()), sum(&c));
1180
1181 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1183 let c = Int16Array::new((1..=100).collect(), Some(validity));
1184 assert_eq!(Some((1..=100).filter(|i| i % 3 == 0).sum()), sum(&c));
1185 }
1186
1187 #[test]
1188 fn test_primitive_array_sum_large_8() {
1189 let c = UInt8Array::new((1..=100).collect(), None);
1190 assert_eq!(
1191 Some((1..=100).fold(0_u8, |a, x| a.wrapping_add(x))),
1192 sum(&c)
1193 );
1194
1195 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1197 let c = UInt8Array::new((1..=100).collect(), Some(validity));
1198 assert_eq!(
1199 Some(
1200 (1..=100)
1201 .filter(|i| i % 3 == 0)
1202 .fold(0_u8, |a, x| a.wrapping_add(x))
1203 ),
1204 sum(&c)
1205 );
1206 }
1207
1208 #[test]
1209 fn test_primitive_array_bit_and() {
1210 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1211 assert_eq!(0, bit_and(&a).unwrap());
1212 }
1213
1214 #[test]
1215 fn test_primitive_array_bit_and_with_nulls() {
1216 let a = Int32Array::from(vec![None, Some(2), Some(3), None, None]);
1217 assert_eq!(2, bit_and(&a).unwrap());
1218 }
1219
1220 #[test]
1221 fn test_primitive_array_bit_and_all_nulls() {
1222 let a = Int32Array::from(vec![None, None, None]);
1223 assert_eq!(None, bit_and(&a));
1224 }
1225
1226 #[test]
1227 fn test_primitive_array_bit_or() {
1228 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1229 assert_eq!(7, bit_or(&a).unwrap());
1230 }
1231
1232 #[test]
1233 fn test_primitive_array_bit_or_with_nulls() {
1234 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
1235 assert_eq!(7, bit_or(&a).unwrap());
1236 }
1237
1238 #[test]
1239 fn test_primitive_array_bit_or_all_nulls() {
1240 let a = Int32Array::from(vec![None, None, None]);
1241 assert_eq!(None, bit_or(&a));
1242 }
1243
1244 #[test]
1245 fn test_primitive_array_bit_xor() {
1246 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1247 assert_eq!(1, bit_xor(&a).unwrap());
1248 }
1249
1250 #[test]
1251 fn test_primitive_array_bit_xor_with_nulls() {
1252 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
1253 assert_eq!(4, bit_xor(&a).unwrap());
1254 }
1255
1256 #[test]
1257 fn test_primitive_array_bit_xor_all_nulls() {
1258 let a = Int32Array::from(vec![None, None, None]);
1259 assert_eq!(None, bit_xor(&a));
1260 }
1261
1262 #[test]
1263 fn test_primitive_array_bool_and() {
1264 let a = BooleanArray::from(vec![true, false, true, false, true]);
1265 assert!(!bool_and(&a).unwrap());
1266 }
1267
1268 #[test]
1269 fn test_primitive_array_bool_and_with_nulls() {
1270 let a = BooleanArray::from(vec![None, Some(true), Some(true), None, Some(true)]);
1271 assert!(bool_and(&a).unwrap());
1272 }
1273
1274 #[test]
1275 fn test_primitive_array_bool_and_all_nulls() {
1276 let a = BooleanArray::from(vec![None, None, None]);
1277 assert_eq!(None, bool_and(&a));
1278 }
1279
1280 #[test]
1281 fn test_primitive_array_bool_or() {
1282 let a = BooleanArray::from(vec![true, false, true, false, true]);
1283 assert!(bool_or(&a).unwrap());
1284 }
1285
1286 #[test]
1287 fn test_primitive_array_bool_or_with_nulls() {
1288 let a = BooleanArray::from(vec![None, Some(false), Some(false), None, Some(false)]);
1289 assert!(!bool_or(&a).unwrap());
1290 }
1291
1292 #[test]
1293 fn test_primitive_array_bool_or_all_nulls() {
1294 let a = BooleanArray::from(vec![None, None, None]);
1295 assert_eq!(None, bool_or(&a));
1296 }
1297
1298 #[test]
1299 fn test_primitive_array_min_max() {
1300 let a = Int32Array::from(vec![5, 6, 7, 8, 9]);
1301 assert_eq!(5, min(&a).unwrap());
1302 assert_eq!(9, max(&a).unwrap());
1303 }
1304
1305 #[test]
1306 fn test_primitive_array_min_max_with_nulls() {
1307 let a = Int32Array::from(vec![Some(5), None, None, Some(8), Some(9)]);
1308 assert_eq!(5, min(&a).unwrap());
1309 assert_eq!(9, max(&a).unwrap());
1310 }
1311
1312 #[test]
1313 fn test_primitive_min_max_1() {
1314 let a = Int32Array::from(vec![None, None, Some(5), Some(2)]);
1315 assert_eq!(Some(2), min(&a));
1316 assert_eq!(Some(5), max(&a));
1317 }
1318
1319 #[test]
1320 fn test_primitive_min_max_float_large_nonnull_array() {
1321 let a: Float64Array = (0..256).map(|i| Some((i + 1) as f64)).collect();
1322 assert_eq!(Some(1.0), min(&a));
1324 assert_eq!(Some(256.0), max(&a));
1325
1326 let a: Float64Array = (0..255).map(|i| Some((i + 1) as f64)).collect();
1328 assert_eq!(Some(255.0), max(&a));
1329
1330 let a: Float64Array = (0..257).map(|i| Some((i + 1) as f64)).collect();
1332 assert_eq!(Some(257.0), max(&a));
1333 }
1334
1335 #[test]
1336 fn test_primitive_min_max_float_large_nullable_array() {
1337 let a: Float64Array = (0..256)
1338 .map(|i| {
1339 if (i + 1) % 3 == 0 {
1340 None
1341 } else {
1342 Some((i + 1) as f64)
1343 }
1344 })
1345 .collect();
1346 assert_eq!(Some(1.0), min(&a));
1348 assert_eq!(Some(256.0), max(&a));
1349
1350 let a: Float64Array = (0..256)
1351 .map(|i| {
1352 if i == 0 || i == 255 {
1353 None
1354 } else {
1355 Some((i + 1) as f64)
1356 }
1357 })
1358 .collect();
1359 assert_eq!(Some(2.0), min(&a));
1361 assert_eq!(Some(255.0), max(&a));
1362
1363 let a: Float64Array = (0..256)
1364 .map(|i| if i != 100 { None } else { Some((i) as f64) })
1365 .collect();
1366 assert_eq!(Some(100.0), min(&a));
1368 assert_eq!(Some(100.0), max(&a));
1369
1370 let a: Float64Array = (0..255).map(|i| Some((i + 1) as f64)).collect();
1372 assert_eq!(Some(255.0), max(&a));
1373
1374 let a: Float64Array = (0..257).map(|i| Some((i + 1) as f64)).collect();
1376 assert_eq!(Some(257.0), max(&a));
1377 }
1378
1379 #[test]
1380 fn test_primitive_min_max_float_edge_cases() {
1381 let a: Float64Array = (0..100).map(|_| Some(f64::NEG_INFINITY)).collect();
1382 assert_eq!(Some(f64::NEG_INFINITY), min(&a));
1383 assert_eq!(Some(f64::NEG_INFINITY), max(&a));
1384
1385 let a: Float64Array = (0..100).map(|_| Some(f64::MIN)).collect();
1386 assert_eq!(Some(f64::MIN), min(&a));
1387 assert_eq!(Some(f64::MIN), max(&a));
1388
1389 let a: Float64Array = (0..100).map(|_| Some(f64::MAX)).collect();
1390 assert_eq!(Some(f64::MAX), min(&a));
1391 assert_eq!(Some(f64::MAX), max(&a));
1392
1393 let a: Float64Array = (0..100).map(|_| Some(f64::INFINITY)).collect();
1394 assert_eq!(Some(f64::INFINITY), min(&a));
1395 assert_eq!(Some(f64::INFINITY), max(&a));
1396 }
1397
1398 #[test]
1399 fn test_primitive_min_max_float_all_nans_non_null() {
1400 let a: Float64Array = (0..100).map(|_| Some(f64::NAN)).collect();
1401 assert!(max(&a).unwrap().is_nan());
1402 assert!(min(&a).unwrap().is_nan());
1403 }
1404
1405 #[test]
1406 fn test_primitive_min_max_float_negative_nan() {
1407 let a: Float64Array =
1408 Float64Array::from(vec![f64::NEG_INFINITY, f64::NAN, f64::INFINITY, -f64::NAN]);
1409 let max = max(&a).unwrap();
1410 let min = min(&a).unwrap();
1411 assert!(max.is_nan());
1412 assert!(max.is_sign_positive());
1413
1414 assert!(min.is_nan());
1415 assert!(min.is_sign_negative());
1416 }
1417
1418 #[test]
1419 fn test_primitive_min_max_float_first_nan_nonnull() {
1420 let a: Float64Array = (0..100)
1421 .map(|i| {
1422 if i == 0 {
1423 Some(f64::NAN)
1424 } else {
1425 Some(i as f64)
1426 }
1427 })
1428 .collect();
1429 assert_eq!(Some(1.0), min(&a));
1430 assert!(max(&a).unwrap().is_nan());
1431 }
1432
1433 #[test]
1434 fn test_primitive_min_max_float_last_nan_nonnull() {
1435 let a: Float64Array = (0..100)
1436 .map(|i| {
1437 if i == 99 {
1438 Some(f64::NAN)
1439 } else {
1440 Some((i + 1) as f64)
1441 }
1442 })
1443 .collect();
1444 assert_eq!(Some(1.0), min(&a));
1445 assert!(max(&a).unwrap().is_nan());
1446 }
1447
1448 #[test]
1449 fn test_primitive_min_max_float_first_nan_nullable() {
1450 let a: Float64Array = (0..100)
1451 .map(|i| {
1452 if i == 0 {
1453 Some(f64::NAN)
1454 } else if i % 2 == 0 {
1455 None
1456 } else {
1457 Some(i as f64)
1458 }
1459 })
1460 .collect();
1461 assert_eq!(Some(1.0), min(&a));
1462 assert!(max(&a).unwrap().is_nan());
1463 }
1464
1465 #[test]
1466 fn test_primitive_min_max_float_last_nan_nullable() {
1467 let a: Float64Array = (0..100)
1468 .map(|i| {
1469 if i == 99 {
1470 Some(f64::NAN)
1471 } else if i % 2 == 0 {
1472 None
1473 } else {
1474 Some(i as f64)
1475 }
1476 })
1477 .collect();
1478 assert_eq!(Some(1.0), min(&a));
1479 assert!(max(&a).unwrap().is_nan());
1480 }
1481
1482 #[test]
1483 fn test_primitive_min_max_float_inf_and_nans() {
1484 let a: Float64Array = (0..100)
1485 .map(|i| {
1486 let x = match i % 10 {
1487 0 => f64::NEG_INFINITY,
1488 1 => f64::MIN,
1489 2 => f64::MAX,
1490 4 => f64::INFINITY,
1491 5 => f64::NAN,
1492 _ => i as f64,
1493 };
1494 Some(x)
1495 })
1496 .collect();
1497 assert_eq!(Some(f64::NEG_INFINITY), min(&a));
1498 assert!(max(&a).unwrap().is_nan());
1499 }
1500
1501 fn pad_inputs_and_test_fixed_size_binary(
1502 input: Vec<Option<&[u8]>>,
1503 expected_min: Option<&[u8]>,
1504 expected_max: Option<&[u8]>,
1505 ) {
1506 fn pad_slice(slice: &[u8], len: usize) -> Vec<u8> {
1507 let mut padded = vec![0; len];
1508 padded[..slice.len()].copy_from_slice(slice);
1509 padded
1510 }
1511
1512 let max_len = input
1513 .iter()
1514 .filter_map(|x| x.as_ref().map(|b| b.len()))
1515 .max()
1516 .unwrap_or(0);
1517 let padded_input = input
1518 .iter()
1519 .map(|x| x.as_ref().map(|b| pad_slice(b, max_len)));
1520 let input_arr =
1521 FixedSizeBinaryArray::try_from_sparse_iter_with_size(padded_input, max_len as i32)
1522 .unwrap();
1523 let padded_expected_min = expected_min.map(|b| pad_slice(b, max_len));
1524 let padded_expected_max = expected_max.map(|b| pad_slice(b, max_len));
1525
1526 assert_eq!(
1527 padded_expected_min.as_deref(),
1528 min_fixed_size_binary(&input_arr)
1529 );
1530 assert_eq!(
1531 padded_expected_max.as_deref(),
1532 max_fixed_size_binary(&input_arr)
1533 );
1534 }
1535
1536 macro_rules! test_binary {
1537 ($NAME:ident, $ARRAY:expr, $EXPECTED_MIN:expr, $EXPECTED_MAX: expr) => {
1538 #[test]
1539 fn $NAME() {
1540 let binary = BinaryArray::from($ARRAY);
1541 assert_eq!($EXPECTED_MIN, min_binary(&binary));
1542 assert_eq!($EXPECTED_MAX, max_binary(&binary));
1543
1544 let large_binary = LargeBinaryArray::from($ARRAY);
1545 assert_eq!($EXPECTED_MIN, min_binary(&large_binary));
1546 assert_eq!($EXPECTED_MAX, max_binary(&large_binary));
1547
1548 let binary_view = BinaryViewArray::from($ARRAY);
1549 assert_eq!($EXPECTED_MIN, min_binary_view(&binary_view));
1550 assert_eq!($EXPECTED_MAX, max_binary_view(&binary_view));
1551
1552 pad_inputs_and_test_fixed_size_binary($ARRAY, $EXPECTED_MIN, $EXPECTED_MAX);
1553 }
1554 };
1555 }
1556
1557 test_binary!(
1558 test_binary_min_max_with_nulls,
1559 vec![
1560 Some("b01234567890123".as_bytes()), None,
1562 None,
1563 Some(b"a"),
1564 Some(b"c"),
1565 Some(b"abcdedfg0123456"),
1566 ],
1567 Some("a".as_bytes()),
1568 Some("c".as_bytes())
1569 );
1570
1571 test_binary!(
1572 test_binary_min_max_no_null,
1573 vec![
1574 Some("b".as_bytes()),
1575 Some(b"abcdefghijklmnopqrst"), Some(b"c"),
1577 Some(b"b01234567890123"), ],
1579 Some("abcdefghijklmnopqrst".as_bytes()),
1580 Some("c".as_bytes())
1581 );
1582
1583 test_binary!(test_binary_min_max_all_nulls, vec![None, None], None, None);
1584
1585 test_binary!(
1586 test_binary_min_max_1,
1587 vec![
1588 None,
1589 Some("b01234567890123435".as_bytes()), None,
1591 Some(b"b0123xxxxxxxxxxx"),
1592 Some(b"a")
1593 ],
1594 Some("a".as_bytes()),
1595 Some("b0123xxxxxxxxxxx".as_bytes())
1596 );
1597
1598 macro_rules! test_string {
1599 ($NAME:ident, $ARRAY:expr, $EXPECTED_MIN:expr, $EXPECTED_MAX: expr) => {
1600 #[test]
1601 fn $NAME() {
1602 let string = StringArray::from($ARRAY);
1603 assert_eq!($EXPECTED_MIN, min_string(&string));
1604 assert_eq!($EXPECTED_MAX, max_string(&string));
1605
1606 let large_string = LargeStringArray::from($ARRAY);
1607 assert_eq!($EXPECTED_MIN, min_string(&large_string));
1608 assert_eq!($EXPECTED_MAX, max_string(&large_string));
1609
1610 let string_view = StringViewArray::from($ARRAY);
1611 assert_eq!($EXPECTED_MIN, min_string_view(&string_view));
1612 assert_eq!($EXPECTED_MAX, max_string_view(&string_view));
1613 }
1614 };
1615 }
1616
1617 test_string!(
1618 test_string_min_max_with_nulls,
1619 vec![
1620 Some("b012345678901234"), None,
1622 None,
1623 Some("a"),
1624 Some("c"),
1625 Some("b0123xxxxxxxxxxx")
1626 ],
1627 Some("a"),
1628 Some("c")
1629 );
1630
1631 test_string!(
1632 test_string_min_max_no_null,
1633 vec![
1634 Some("b"),
1635 Some("b012345678901234"), Some("a"),
1637 Some("b012xxxxxxxxxxxx")
1638 ],
1639 Some("a"),
1640 Some("b012xxxxxxxxxxxx")
1641 );
1642
1643 test_string!(
1644 test_string_min_max_all_nulls,
1645 Vec::<Option<&str>>::from_iter([None, None]),
1646 None,
1647 None
1648 );
1649
1650 test_string!(
1651 test_string_min_max_1,
1652 vec![
1653 None,
1654 Some("c12345678901234"), None,
1656 Some("b"),
1657 Some("c1234xxxxxxxxxx")
1658 ],
1659 Some("b"),
1660 Some("c1234xxxxxxxxxx")
1661 );
1662
1663 test_string!(
1664 test_string_min_max_empty,
1665 Vec::<Option<&str>>::new(),
1666 None,
1667 None
1668 );
1669
1670 #[test]
1671 fn test_boolean_min_max_empty() {
1672 let a = BooleanArray::from(vec![] as Vec<Option<bool>>);
1673 assert_eq!(None, min_boolean(&a));
1674 assert_eq!(None, max_boolean(&a));
1675 }
1676
1677 #[test]
1678 fn test_boolean_min_max_all_null() {
1679 let a = BooleanArray::from(vec![None, None]);
1680 assert_eq!(None, min_boolean(&a));
1681 assert_eq!(None, max_boolean(&a));
1682 }
1683
1684 #[test]
1685 fn test_boolean_min_max_no_null() {
1686 let a = BooleanArray::from(vec![Some(true), Some(false), Some(true)]);
1687 assert_eq!(Some(false), min_boolean(&a));
1688 assert_eq!(Some(true), max_boolean(&a));
1689 }
1690
1691 #[test]
1692 fn test_boolean_min_max() {
1693 let a = BooleanArray::from(vec![Some(true), Some(true), None, Some(false), None]);
1694 assert_eq!(Some(false), min_boolean(&a));
1695 assert_eq!(Some(true), max_boolean(&a));
1696
1697 let a = BooleanArray::from(vec![None, Some(true), None, Some(false), None]);
1698 assert_eq!(Some(false), min_boolean(&a));
1699 assert_eq!(Some(true), max_boolean(&a));
1700
1701 let a = BooleanArray::from(vec![Some(false), Some(true), None, Some(false), None]);
1702 assert_eq!(Some(false), min_boolean(&a));
1703 assert_eq!(Some(true), max_boolean(&a));
1704
1705 let a = BooleanArray::from(vec![Some(true), None]);
1706 assert_eq!(Some(true), min_boolean(&a));
1707 assert_eq!(Some(true), max_boolean(&a));
1708
1709 let a = BooleanArray::from(vec![Some(false), None]);
1710 assert_eq!(Some(false), min_boolean(&a));
1711 assert_eq!(Some(false), max_boolean(&a));
1712
1713 let a = BooleanArray::from(vec![Some(true)]);
1714 assert_eq!(Some(true), min_boolean(&a));
1715 assert_eq!(Some(true), max_boolean(&a));
1716
1717 let a = BooleanArray::from(vec![Some(false)]);
1718 assert_eq!(Some(false), min_boolean(&a));
1719 assert_eq!(Some(false), max_boolean(&a));
1720 }
1721
1722 #[test]
1723 fn test_boolean_min_max_smaller() {
1724 let a = BooleanArray::from(vec![Some(false)]);
1725 assert_eq!(Some(false), min_boolean(&a));
1726 assert_eq!(Some(false), max_boolean(&a));
1727
1728 let a = BooleanArray::from(vec![None, Some(false)]);
1729 assert_eq!(Some(false), min_boolean(&a));
1730 assert_eq!(Some(false), max_boolean(&a));
1731
1732 let a = BooleanArray::from(vec![None, Some(true)]);
1733 assert_eq!(Some(true), min_boolean(&a));
1734 assert_eq!(Some(true), max_boolean(&a));
1735
1736 let a = BooleanArray::from(vec![Some(true)]);
1737 assert_eq!(Some(true), min_boolean(&a));
1738 assert_eq!(Some(true), max_boolean(&a));
1739 }
1740
1741 #[test]
1742 fn test_boolean_min_max_64_true_64_false() {
1743 let mut no_nulls = BooleanBuilder::new();
1744 no_nulls.append_slice(&[true; 64]);
1745 no_nulls.append_slice(&[false; 64]);
1746 let no_nulls = no_nulls.finish();
1747
1748 assert_eq!(Some(false), min_boolean(&no_nulls));
1749 assert_eq!(Some(true), max_boolean(&no_nulls));
1750
1751 let mut with_nulls = BooleanBuilder::new();
1752 with_nulls.append_slice(&[true; 31]);
1753 with_nulls.append_null();
1754 with_nulls.append_slice(&[true; 32]);
1755 with_nulls.append_slice(&[false; 1]);
1756 with_nulls.append_nulls(63);
1757 let with_nulls = with_nulls.finish();
1758
1759 assert_eq!(Some(false), min_boolean(&with_nulls));
1760 assert_eq!(Some(true), max_boolean(&with_nulls));
1761 }
1762
1763 #[test]
1764 fn test_boolean_min_max_64_false_64_true() {
1765 let mut no_nulls = BooleanBuilder::new();
1766 no_nulls.append_slice(&[false; 64]);
1767 no_nulls.append_slice(&[true; 64]);
1768 let no_nulls = no_nulls.finish();
1769
1770 assert_eq!(Some(false), min_boolean(&no_nulls));
1771 assert_eq!(Some(true), max_boolean(&no_nulls));
1772
1773 let mut with_nulls = BooleanBuilder::new();
1774 with_nulls.append_slice(&[false; 31]);
1775 with_nulls.append_null();
1776 with_nulls.append_slice(&[false; 32]);
1777 with_nulls.append_slice(&[true; 1]);
1778 with_nulls.append_nulls(63);
1779 let with_nulls = with_nulls.finish();
1780
1781 assert_eq!(Some(false), min_boolean(&with_nulls));
1782 assert_eq!(Some(true), max_boolean(&with_nulls));
1783 }
1784
1785 #[test]
1786 fn test_boolean_min_max_96_true() {
1787 let mut no_nulls = BooleanBuilder::new();
1788 no_nulls.append_slice(&[true; 96]);
1789 let no_nulls = no_nulls.finish();
1790
1791 assert_eq!(Some(true), min_boolean(&no_nulls));
1792 assert_eq!(Some(true), max_boolean(&no_nulls));
1793
1794 let mut with_nulls = BooleanBuilder::new();
1795 with_nulls.append_slice(&[true; 31]);
1796 with_nulls.append_null();
1797 with_nulls.append_slice(&[true; 32]);
1798 with_nulls.append_slice(&[true; 31]);
1799 with_nulls.append_null();
1800 let with_nulls = with_nulls.finish();
1801
1802 assert_eq!(Some(true), min_boolean(&with_nulls));
1803 assert_eq!(Some(true), max_boolean(&with_nulls));
1804 }
1805
1806 #[test]
1807 fn test_boolean_min_max_96_false() {
1808 let mut no_nulls = BooleanBuilder::new();
1809 no_nulls.append_slice(&[false; 96]);
1810 let no_nulls = no_nulls.finish();
1811
1812 assert_eq!(Some(false), min_boolean(&no_nulls));
1813 assert_eq!(Some(false), max_boolean(&no_nulls));
1814
1815 let mut with_nulls = BooleanBuilder::new();
1816 with_nulls.append_slice(&[false; 31]);
1817 with_nulls.append_null();
1818 with_nulls.append_slice(&[false; 32]);
1819 with_nulls.append_slice(&[false; 31]);
1820 with_nulls.append_null();
1821 let with_nulls = with_nulls.finish();
1822
1823 assert_eq!(Some(false), min_boolean(&with_nulls));
1824 assert_eq!(Some(false), max_boolean(&with_nulls));
1825 }
1826
1827 #[test]
1828 fn test_sum_dyn() {
1829 let values = Int8Array::from_iter_values([10_i8, 11, 12, 13, 14, 15, 16, 17]);
1830 let values = Arc::new(values) as ArrayRef;
1831 let keys = Int8Array::from_iter_values([2_i8, 3, 4]);
1832
1833 let dict_array = DictionaryArray::new(keys, values.clone());
1834 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1835 assert_eq!(39, sum_array::<Int8Type, _>(array).unwrap());
1836
1837 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1838 assert_eq!(15, sum_array::<Int32Type, _>(&a).unwrap());
1839
1840 let keys = Int8Array::from(vec![Some(2_i8), None, Some(4)]);
1841 let dict_array = DictionaryArray::new(keys, values.clone());
1842 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1843 assert_eq!(26, sum_array::<Int8Type, _>(array).unwrap());
1844
1845 let keys = Int8Array::from(vec![None, None, None]);
1846 let dict_array = DictionaryArray::new(keys, values.clone());
1847 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1848 assert!(sum_array::<Int8Type, _>(array).is_none());
1849 }
1850
1851 #[test]
1852 fn test_max_min_dyn() {
1853 let values = Int8Array::from_iter_values([10_i8, 11, 12, 13, 14, 15, 16, 17]);
1854 let keys = Int8Array::from_iter_values([2_i8, 3, 4]);
1855 let values = Arc::new(values) as ArrayRef;
1856
1857 let dict_array = DictionaryArray::new(keys, values.clone());
1858 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1859 assert_eq!(14, max_array::<Int8Type, _>(array).unwrap());
1860
1861 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1862 assert_eq!(12, min_array::<Int8Type, _>(array).unwrap());
1863
1864 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1865 assert_eq!(5, max_array::<Int32Type, _>(&a).unwrap());
1866 assert_eq!(1, min_array::<Int32Type, _>(&a).unwrap());
1867
1868 let keys = Int8Array::from(vec![Some(2_i8), None, Some(7)]);
1869 let dict_array = DictionaryArray::new(keys, values.clone());
1870 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1871 assert_eq!(17, max_array::<Int8Type, _>(array).unwrap());
1872 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1873 assert_eq!(12, min_array::<Int8Type, _>(array).unwrap());
1874
1875 let keys = Int8Array::from(vec![None, None, None]);
1876 let dict_array = DictionaryArray::new(keys, values.clone());
1877 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1878 assert!(max_array::<Int8Type, _>(array).is_none());
1879 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1880 assert!(min_array::<Int8Type, _>(array).is_none());
1881 }
1882
1883 #[test]
1884 fn test_max_min_dyn_nan() {
1885 let values = Float32Array::from(vec![5.0_f32, 2.0_f32, f32::NAN]);
1886 let keys = Int8Array::from_iter_values([0_i8, 1, 2]);
1887
1888 let dict_array = DictionaryArray::new(keys, Arc::new(values));
1889 let array = dict_array.downcast_dict::<Float32Array>().unwrap();
1890 assert!(max_array::<Float32Type, _>(array).unwrap().is_nan());
1891
1892 let array = dict_array.downcast_dict::<Float32Array>().unwrap();
1893 assert_eq!(2.0_f32, min_array::<Float32Type, _>(array).unwrap());
1894 }
1895
1896 #[test]
1897 fn test_min_max_sliced_primitive() {
1898 let expected = Some(4.0);
1899 let input: Float64Array = vec![None, Some(4.0)].into_iter().collect();
1900 let actual = min(&input);
1901 assert_eq!(actual, expected);
1902 let actual = max(&input);
1903 assert_eq!(actual, expected);
1904
1905 let sliced_input: Float64Array = vec![None, None, None, None, None, Some(4.0)]
1906 .into_iter()
1907 .collect();
1908 let sliced_input = sliced_input.slice(4, 2);
1909
1910 assert_eq!(&sliced_input, &input);
1911
1912 let actual = min(&sliced_input);
1913 assert_eq!(actual, expected);
1914 let actual = max(&sliced_input);
1915 assert_eq!(actual, expected);
1916 }
1917
1918 #[test]
1919 fn test_min_max_sliced_boolean() {
1920 let expected = Some(true);
1921 let input: BooleanArray = vec![None, Some(true)].into_iter().collect();
1922 let actual = min_boolean(&input);
1923 assert_eq!(actual, expected);
1924 let actual = max_boolean(&input);
1925 assert_eq!(actual, expected);
1926
1927 let sliced_input: BooleanArray = vec![None, None, None, None, None, Some(true)]
1928 .into_iter()
1929 .collect();
1930 let sliced_input = sliced_input.slice(4, 2);
1931
1932 assert_eq!(sliced_input, input);
1933
1934 let actual = min_boolean(&sliced_input);
1935 assert_eq!(actual, expected);
1936 let actual = max_boolean(&sliced_input);
1937 assert_eq!(actual, expected);
1938 }
1939
1940 #[test]
1941 fn test_min_max_sliced_string() {
1942 let expected = Some("foo");
1943 let input: StringArray = vec![None, Some("foo")].into_iter().collect();
1944 let actual = min_string(&input);
1945 assert_eq!(actual, expected);
1946 let actual = max_string(&input);
1947 assert_eq!(actual, expected);
1948
1949 let sliced_input: StringArray = vec![None, None, None, None, None, Some("foo")]
1950 .into_iter()
1951 .collect();
1952 let sliced_input = sliced_input.slice(4, 2);
1953
1954 assert_eq!(&sliced_input, &input);
1955
1956 let actual = min_string(&sliced_input);
1957 assert_eq!(actual, expected);
1958 let actual = max_string(&sliced_input);
1959 assert_eq!(actual, expected);
1960 }
1961
1962 #[test]
1963 fn test_min_max_sliced_binary() {
1964 let expected: Option<&[u8]> = Some(&[5]);
1965 let input: BinaryArray = vec![None, Some(&[5])].into_iter().collect();
1966 let actual = min_binary(&input);
1967 assert_eq!(actual, expected);
1968 let actual = max_binary(&input);
1969 assert_eq!(actual, expected);
1970
1971 let sliced_input: BinaryArray = vec![None, None, None, None, None, Some(&[5])]
1972 .into_iter()
1973 .collect();
1974 let sliced_input = sliced_input.slice(4, 2);
1975
1976 assert_eq!(&sliced_input, &input);
1977
1978 let actual = min_binary(&sliced_input);
1979 assert_eq!(actual, expected);
1980 let actual = max_binary(&sliced_input);
1981 assert_eq!(actual, expected);
1982 }
1983
1984 #[test]
1985 fn test_sum_overflow() {
1986 let a = Int32Array::from(vec![i32::MAX, 1]);
1987
1988 assert_eq!(sum(&a).unwrap(), -2147483648);
1989 assert_eq!(sum_array::<Int32Type, _>(&a).unwrap(), -2147483648);
1990 }
1991
1992 #[test]
1993 fn test_sum_checked_overflow() {
1994 let a = Int32Array::from(vec![i32::MAX, 1]);
1995
1996 sum_checked(&a).expect_err("overflow should be detected");
1997 sum_array_checked::<Int32Type, _>(&a).expect_err("overflow should be detected");
1998 }
1999
2000 fn make_run_array<'a, I: RunEndIndexType, V: ArrowNumericType, ItemType>(
2002 values: impl IntoIterator<Item = &'a ItemType>,
2003 ) -> RunArray<I>
2004 where
2005 ItemType: Clone + Into<Option<V::Native>> + 'static,
2006 {
2007 let mut builder = arrow_array::builder::PrimitiveRunBuilder::<I, V>::new();
2008 for v in values.into_iter() {
2009 builder.append_option((*v).clone().into());
2010 }
2011 builder.finish()
2012 }
2013
2014 #[test]
2015 fn test_ree_sum_array_basic() {
2016 let run_array = make_run_array::<Int16Type, Int32Type, _>(&[10, 10, 20, 30, 30, 30]);
2017 let typed_array = run_array.downcast::<Int32Array>().unwrap();
2018
2019 let result = sum_array::<Int32Type, _>(typed_array);
2020 assert_eq!(result, Some(130));
2021
2022 let result = sum_array_checked::<Int32Type, _>(typed_array).unwrap();
2023 assert_eq!(result, Some(130));
2024 }
2025
2026 #[test]
2027 fn test_ree_sum_array_empty() {
2028 let run_array = make_run_array::<Int16Type, Int32Type, i32>(&[]);
2029 let typed_array = run_array.downcast::<Int32Array>().unwrap();
2030
2031 let result = sum_array::<Int32Type, _>(typed_array);
2032 assert_eq!(result, None);
2033
2034 let result = sum_array_checked::<Int32Type, _>(typed_array).unwrap();
2035 assert_eq!(result, None);
2036 }
2037
2038 #[test]
2039 fn test_ree_sum_array_with_nulls() {
2040 let run_array =
2041 make_run_array::<Int16Type, Int32Type, _>(&[Some(10), None, Some(20), None, Some(30)]);
2042 let typed_array = run_array.downcast::<Int32Array>().unwrap();
2043
2044 let result = sum_array::<Int32Type, _>(typed_array);
2045 assert_eq!(result, Some(60));
2046
2047 let result = sum_array_checked::<Int32Type, _>(typed_array).unwrap();
2048 assert_eq!(result, Some(60));
2049 }
2050
2051 #[test]
2052 fn test_ree_sum_array_with_only_nulls() {
2053 let run_array = make_run_array::<Int16Type, Int16Type, _>(&[None, None, None, None, None]);
2054 let typed_array = run_array.downcast::<Int16Array>().unwrap();
2055
2056 let result = sum_array::<Int16Type, _>(typed_array);
2057 assert_eq!(result, None);
2058
2059 let result = sum_array_checked::<Int16Type, _>(typed_array).unwrap();
2060 assert_eq!(result, None);
2061 }
2062
2063 #[test]
2064 fn test_ree_sum_array_overflow() {
2065 let run_array = make_run_array::<Int16Type, Int8Type, _>(&[126, 2]);
2066 let typed_array = run_array.downcast::<Int8Array>().unwrap();
2067
2068 let result = sum_array::<Int8Type, _>(typed_array);
2070 assert_eq!(result, Some(-128));
2071
2072 let result = sum_array_checked::<Int8Type, _>(typed_array);
2073 assert!(result.is_err());
2074 }
2075
2076 #[test]
2077 fn test_ree_sum_array_sliced() {
2078 let run_array = make_run_array::<Int16Type, UInt8Type, _>(&[0, 10, 10, 10, 20, 30, 30, 30]);
2079 let sliced = run_array.slice(2, 5);
2081 let typed_array = sliced.downcast::<UInt8Array>().unwrap();
2082
2083 let result = sum_array::<UInt8Type, _>(typed_array);
2084 assert_eq!(result, Some(100));
2085
2086 let result = sum_array_checked::<UInt8Type, _>(typed_array).unwrap();
2087 assert_eq!(result, Some(100));
2088 }
2089
2090 #[test]
2091 fn test_ree_min_max_array_basic() {
2092 let run_array = make_run_array::<Int16Type, Int32Type, _>(&[30, 30, 10, 20, 20]);
2093 let typed_array = run_array.downcast::<Int32Array>().unwrap();
2094
2095 let result = min_array::<Int32Type, _>(typed_array);
2096 assert_eq!(result, Some(10));
2097
2098 let result = max_array::<Int32Type, _>(typed_array);
2099 assert_eq!(result, Some(30));
2100 }
2101
2102 #[test]
2103 fn test_ree_min_max_array_empty() {
2104 let run_array = make_run_array::<Int16Type, Int32Type, i32>(&[]);
2105 let typed_array = run_array.downcast::<Int32Array>().unwrap();
2106
2107 let result = min_array::<Int32Type, _>(typed_array);
2108 assert_eq!(result, None);
2109
2110 let result = max_array::<Int32Type, _>(typed_array);
2111 assert_eq!(result, None);
2112 }
2113
2114 #[test]
2115 fn test_ree_min_max_array_float() {
2116 let run_array = make_run_array::<Int16Type, Float64Type, _>(&[5.5, 5.5, 2.1, 8.9, 8.9]);
2117 let typed_array = run_array.downcast::<Float64Array>().unwrap();
2118
2119 let result = min_array::<Float64Type, _>(typed_array);
2120 assert_eq!(result, Some(2.1));
2121
2122 let result = max_array::<Float64Type, _>(typed_array);
2123 assert_eq!(result, Some(8.9));
2124 }
2125
2126 #[test]
2127 fn test_ree_min_max_array_with_nulls() {
2128 let run_array = make_run_array::<Int16Type, UInt8Type, _>(&[None, Some(10)]);
2129 let typed_array = run_array.downcast::<UInt8Array>().unwrap();
2130
2131 let result = min_array::<UInt8Type, _>(typed_array);
2132 assert_eq!(result, Some(10));
2133
2134 let result = max_array::<UInt8Type, _>(typed_array);
2135 assert_eq!(result, Some(10));
2136 }
2137
2138 #[test]
2139 fn test_ree_min_max_array_sliced() {
2140 let run_array = make_run_array::<Int16Type, Int32Type, _>(&[0, 30, 30, 10, 20, 20, 100]);
2141 let sliced = run_array.slice(1, 5);
2143 let typed_array = sliced.downcast::<Int32Array>().unwrap();
2144
2145 let result = min_array::<Int32Type, _>(typed_array);
2146 assert_eq!(result, Some(10));
2147
2148 let result = max_array::<Int32Type, _>(typed_array);
2149 assert_eq!(result, Some(30));
2150 }
2151
2152 #[test]
2153 fn test_ree_min_max_array_sliced_mid_run() {
2154 let run_array = make_run_array::<Int16Type, Int32Type, _>(&[0, 0, 30, 10, 20, 100, 100]);
2155 let sliced = run_array.slice(1, 5);
2157 let typed_array = sliced.downcast::<Int32Array>().unwrap();
2158
2159 let result = min_array::<Int32Type, _>(typed_array);
2160 assert_eq!(result, Some(0));
2161
2162 let result = max_array::<Int32Type, _>(typed_array);
2163 assert_eq!(result, Some(100));
2164 }
2165}