Skip to main content

arrow_select/
take.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5//! Defines take kernel for [Array]
6
7use std::fmt::Display;
8use std::mem::ManuallyDrop;
9use std::sync::Arc;
10
11use arrow_array::builder::UInt32Builder;
12use arrow_array::cast::AsArray;
13use arrow_array::types::*;
14use arrow_array::*;
15use arrow_buffer::{
16    ArrowNativeType, BooleanBuffer, Buffer, MutableBuffer, NullBuffer, NullBufferBuilder,
17    OffsetBuffer, RunEndBuffer, ScalarBuffer, bit_util,
18};
19use arrow_cmp::make_comparator;
20use arrow_data::{ArrayData, transform::MutableArrayData};
21use arrow_schema::{ArrowError, DataType, FieldRef, SortOptions, UnionFields, UnionMode};
22
23use num_traits::{CheckedAdd, Zero};
24
25/// Take elements by index from [Array], creating a new [Array] from those indexes.
26///
27/// ```text
28/// ┌─────────────────┐      ┌─────────┐                              ┌─────────────────┐
29/// │        A        │      │    0    │                              │        A        │
30/// ├─────────────────┤      ├─────────┤                              ├─────────────────┤
31/// │        D        │      │    2    │                              │        B        │
32/// ├─────────────────┤      ├─────────┤   take(values, indices)      ├─────────────────┤
33/// │        B        │      │    3    │ ─────────────────────────▶   │        C        │
34/// ├─────────────────┤      ├─────────┤                              ├─────────────────┤
35/// │        C        │      │    1    │                              │        D        │
36/// ├─────────────────┤      └─────────┘                              └─────────────────┘
37/// │        E        │
38/// └─────────────────┘
39///    values array          indices array                              result
40/// ```
41///
42/// For selecting values by index from multiple arrays see [`crate::interleave`]
43///
44/// Note that this kernel, similar to other kernels in this crate,
45/// will avoid allocating where not necessary. Consequently
46/// the returned array may share buffers with the inputs
47///
48/// # Errors
49/// This function errors whenever:
50/// * An index cannot be casted to `usize` (typically 32 bit architectures)
51/// * An index is out of bounds and `options` is set to check bounds.
52///
53/// # Panics
54///
55/// When `options` is not set to check bounds, taking indexes after `len` will panic.
56///
57/// # See also
58/// * [`BatchCoalescer`]: to filter multiple [`RecordBatch`] and coalesce
59///   the results into a single array.
60///
61/// [`BatchCoalescer`]: crate::coalesce::BatchCoalescer
62///
63/// # Examples
64/// ```
65/// # use arrow_array::{StringArray, UInt32Array, cast::AsArray};
66/// # use arrow_select::take::take;
67/// let values = StringArray::from(vec!["zero", "one", "two"]);
68///
69/// // Take items at index 2, and 1:
70/// let indices = UInt32Array::from(vec![2, 1]);
71/// let taken = take(&values, &indices, None).unwrap();
72/// let taken = taken.as_string::<i32>();
73///
74/// assert_eq!(*taken, StringArray::from(vec!["two", "one"]));
75/// ```
76pub fn take(
77    values: &dyn Array,
78    indices: &dyn Array,
79    options: Option<TakeOptions>,
80) -> Result<ArrayRef, ArrowError> {
81    let options = options.unwrap_or_default();
82    downcast_integer_array!(
83        indices => {
84            let indices = indices.to_indices();
85            if options.check_bounds {
86                check_bounds(values.len(), &indices)?;
87            }
88            take_impl::<_, true>(values, &indices)
89        },
90        d => Err(ArrowError::InvalidArgumentError(format!("Take only supported for integers, got {d:?}")))
91    )
92}
93
94/// For each [ArrayRef] in the [`Vec<ArrayRef>`], take elements by index and create a new
95/// [`Vec<ArrayRef>`] from those indices.
96///
97/// ```text
98/// ┌────────┬────────┐
99/// │        │        │           ┌────────┐                                ┌────────┬────────┐
100/// │   A    │   1    │           │        │                                │        │        │
101/// ├────────┼────────┤           │   0    │                                │   A    │   1    │
102/// │        │        │           ├────────┤                                ├────────┼────────┤
103/// │   D    │   4    │           │        │                                │        │        │
104/// ├────────┼────────┤           │   2    │  take_arrays(values,indices)   │   B    │   2    │
105/// │        │        │           ├────────┤                                ├────────┼────────┤
106/// │   B    │   2    │           │        │  ───────────────────────────►  │        │        │
107/// ├────────┼────────┤           │   3    │                                │   C    │   3    │
108/// │        │        │           ├────────┤                                ├────────┼────────┤
109/// │   C    │   3    │           │        │                                │        │        │
110/// ├────────┼────────┤           │   1    │                                │   D    │   4    │
111/// │        │        │           └────────┘                                └────────┼────────┘
112/// │   E    │   5    │
113/// └────────┴────────┘
114///    values arrays             indices array                                      result
115/// ```
116///
117/// # Errors
118/// This function errors whenever:
119/// * An index cannot be casted to `usize` (typically 32 bit architectures)
120/// * An index is out of bounds and `options` is set to check bounds.
121///
122/// # Panics
123///
124/// When `options` is not set to check bounds, taking indexes after `len` will panic.
125///
126/// # Examples
127/// ```
128/// # use std::sync::Arc;
129/// # use arrow_array::{StringArray, UInt32Array, cast::AsArray};
130/// # use arrow_select::take::{take, take_arrays};
131/// let string_values = Arc::new(StringArray::from(vec!["zero", "one", "two"]));
132/// let values = Arc::new(UInt32Array::from(vec![0, 1, 2]));
133///
134/// // Take items at index 2, and 1:
135/// let indices = UInt32Array::from(vec![2, 1]);
136/// let taken_arrays = take_arrays(&[string_values, values], &indices, None).unwrap();
137/// let taken_string = taken_arrays[0].as_string::<i32>();
138/// assert_eq!(*taken_string, StringArray::from(vec!["two", "one"]));
139/// let taken_values = taken_arrays[1].as_primitive();
140/// assert_eq!(*taken_values, UInt32Array::from(vec![2, 1]));
141/// ```
142pub fn take_arrays(
143    arrays: &[ArrayRef],
144    indices: &dyn Array,
145    options: Option<TakeOptions>,
146) -> Result<Vec<ArrayRef>, ArrowError> {
147    arrays
148        .iter()
149        .map(|array| take(array.as_ref(), indices, options.clone()))
150        .collect()
151}
152
153/// For each [ArrayRef] in the [`Vec<ArrayRef>`], take elements by index and create a new
154/// [`Vec<ArrayRef>`] from those indices, without bounds checking.
155///
156/// # Safety
157///
158/// Caller must ensure all values in `indices` are valid indices into each array
159/// (i.e. `< array.len()`). Out-of-bounds indices will cause undefined behavior.
160///
161/// # Errors
162///
163/// Returns an error if an index value cannot be cast to `usize`.
164pub unsafe fn take_arrays_unchecked(
165    arrays: &[ArrayRef],
166    indices: &dyn Array,
167) -> Result<Vec<ArrayRef>, ArrowError> {
168    downcast_integer_array!(
169        indices => {
170            let indices = indices.to_indices();
171            arrays
172                .iter()
173                .map(|array| take_impl::<_, false>(array.as_ref(), &indices))
174                .collect()
175        },
176        d => Err(ArrowError::InvalidArgumentError(format!("Take only supported for integers, got {d:?}")))
177    )
178}
179
180/// Verifies that the non-null values of `indices` are all `< len`
181fn check_bounds<T: ArrowPrimitiveType>(
182    len: usize,
183    indices: &PrimitiveArray<T>,
184) -> Result<(), ArrowError>
185where
186    T::Native: Display,
187{
188    let Some(len) = T::Native::from_usize(len) else {
189        return if T::DATA_TYPE.is_integer() {
190            // the biggest representable value for T::Native is lower than len, e.g: u8::MAX < 512, no need to check bounds
191            Ok(())
192        } else {
193            Err(ArrowError::ComputeError("Cast to usize failed".to_string()))
194        };
195    };
196
197    // Null slots usually hold in-bounds values, so first check every value with a loop that
198    // vectorizes, and look at validity only if that finds one out of bounds
199    let in_bounds = indices.values().iter().fold(true, |in_bounds, &i| {
200        in_bounds & (i >= T::Native::ZERO) & (i < len)
201    });
202    if in_bounds {
203        Ok(())
204    } else if indices.null_count() > 0 {
205        indices.iter().flatten().try_for_each(|index| {
206            if index >= len {
207                return Err(ArrowError::ComputeError(format!(
208                    "Array index out of bounds, cannot get item at index {index} from {len} entries"
209                )));
210            }
211            Ok(())
212        })
213    } else {
214        for &index in indices.values() {
215            if index < T::Native::ZERO || index >= len {
216                return Err(ArrowError::ComputeError(format!(
217                    "Array index out of bounds, cannot get item at index {index} from {len} entries"
218                )));
219            }
220        }
221        Ok(())
222    }
223}
224
225#[inline(never)]
226fn take_impl<IndexType: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
227    values: &dyn Array,
228    indices: &PrimitiveArray<IndexType>,
229) -> Result<ArrayRef, ArrowError> {
230    if indices.is_empty() {
231        if let DataType::Union(fields, _) = values.data_type()
232            && fields.is_empty()
233        {
234            // `new_empty_array` cannot construct a union with no fields, but an existing empty
235            // union can be sliced without materializing a child array.
236            return Ok(values.slice(0, 0));
237        }
238        return Ok(new_empty_array(values.data_type()));
239    }
240    downcast_primitive_array! {
241        values => Ok(Arc::new(take_primitive::<_, _, VALIDATE_INDICES>(values, indices)?)),
242        DataType::Boolean => {
243            let values = values.as_any().downcast_ref::<BooleanArray>().unwrap();
244            Ok(Arc::new(take_boolean::<_, VALIDATE_INDICES>(values, indices)))
245        }
246        DataType::Utf8 => {
247            Ok(Arc::new(take_bytes::<_, _, VALIDATE_INDICES>(values.as_string::<i32>(), indices)?))
248        }
249        DataType::LargeUtf8 => {
250            Ok(Arc::new(take_bytes::<_, _, VALIDATE_INDICES>(values.as_string::<i64>(), indices)?))
251        }
252        DataType::Utf8View => {
253            Ok(Arc::new(take_byte_view::<_, _, VALIDATE_INDICES>(values.as_string_view(), indices)?))
254        }
255        DataType::List(_) => {
256            Ok(Arc::new(take_list::<_, Int32Type, VALIDATE_INDICES>(values.as_list(), indices)?))
257        }
258        DataType::LargeList(_) => {
259            Ok(Arc::new(take_list::<_, Int64Type, VALIDATE_INDICES>(values.as_list(), indices)?))
260        }
261        DataType::ListView(_) => {
262            Ok(Arc::new(take_list_view::<_, Int32Type, VALIDATE_INDICES>(values.as_list_view(), indices)?))
263        }
264        DataType::LargeListView(_) => {
265            Ok(Arc::new(take_list_view::<_, Int64Type, VALIDATE_INDICES>(values.as_list_view(), indices)?))
266        }
267        DataType::FixedSizeList(_, length) => {
268            let values = values
269                .as_any()
270                .downcast_ref::<FixedSizeListArray>()
271                .unwrap();
272            Ok(Arc::new(take_fixed_size_list::<_, VALIDATE_INDICES>(
273                values,
274                indices,
275                *length as u32,
276            )?))
277        }
278        DataType::Map(field, ordered) => {
279            let list_arr = ListArray::from(values.as_map().clone());
280            let list_data = take_list::<_, Int32Type, VALIDATE_INDICES>(&list_arr, indices)?;
281            let (_, offsets, entries, nulls) = list_data.into_parts();
282            let entries = entries.as_struct().clone();
283            Ok(Arc::new(MapArray::try_new(
284                field.clone(),
285                offsets,
286                entries,
287                nulls,
288                *ordered,
289            )?))
290        }
291        DataType::Struct(fields) => {
292            let array: &StructArray = values.as_struct();
293            let arrays  = array
294                .columns()
295                .iter()
296                .map(|a| take_impl::<_, VALIDATE_INDICES>(a.as_ref(), indices))
297                .collect::<Result<Vec<ArrayRef>, _>>()?;
298            let fields: Vec<(FieldRef, ArrayRef)> =
299                fields.iter().cloned().zip(arrays).collect();
300
301            // Create the null bit buffer.
302            let is_valid: Buffer = indices
303                .iter()
304                .map(|index| {
305                    if let Some(index) = index {
306                        array.is_valid(index.to_usize().unwrap())
307                    } else {
308                        false
309                    }
310                })
311                .collect();
312
313            if fields.is_empty() {
314                let nulls = NullBuffer::new(BooleanBuffer::new(is_valid, 0, indices.len()));
315                Ok(Arc::new(StructArray::new_empty_fields(indices.len(), Some(nulls))))
316            } else {
317                Ok(Arc::new(StructArray::from((fields, is_valid))) as ArrayRef)
318            }
319        }
320        DataType::Dictionary(_, _) => downcast_dictionary_array! {
321            values => Ok(Arc::new(take_dict::<_, _, VALIDATE_INDICES>(values, indices)?)),
322            t => unimplemented!("Take not supported for dictionary type {:?}", t)
323        }
324        DataType::RunEndEncoded(_, _) => downcast_run_array! {
325            values => Ok(Arc::new(take_run(values, indices)?)),
326            t => unimplemented!("Take not supported for run type {:?}", t)
327        }
328        DataType::Binary => {
329            Ok(Arc::new(take_bytes::<_, _, VALIDATE_INDICES>(values.as_binary::<i32>(), indices)?))
330        }
331        DataType::LargeBinary => {
332            Ok(Arc::new(take_bytes::<_, _, VALIDATE_INDICES>(values.as_binary::<i64>(), indices)?))
333        }
334        DataType::BinaryView => {
335            Ok(Arc::new(take_byte_view::<_, _, VALIDATE_INDICES>(values.as_binary_view(), indices)?))
336        }
337        DataType::FixedSizeBinary(size) => {
338            let values = values
339                .as_any()
340                .downcast_ref::<FixedSizeBinaryArray>()
341                .unwrap();
342            Ok(Arc::new(take_fixed_size_binary::<_, VALIDATE_INDICES>(values, indices, *size)?))
343        }
344        DataType::Null => {
345            // Take applied to a null array produces a null array.
346            if values.len() >= indices.len() {
347                // If the existing null array is as big as the indices, we can use a slice of it
348                // to avoid allocating a new null array.
349                Ok(values.slice(0, indices.len()))
350            } else {
351                // If the existing null array isn't big enough, create a new one.
352                Ok(new_null_array(&DataType::Null, indices.len()))
353            }
354        }
355        DataType::Union(fields, UnionMode::Sparse) => {
356            let values = values.as_any().downcast_ref::<UnionArray>().unwrap();
357            let (type_ids, null_type_id) =
358                take_union_type_ids(fields, values.type_ids(), indices)?;
359            let children = fields
360                .iter()
361                .map(|(type_id, _)| {
362                    take_sparse_union_child::<_, VALIDATE_INDICES>(
363                        values.child(type_id),
364                        null_type_id == Some(type_id),
365                        indices,
366                    )
367                })
368                .collect::<Result<Vec<_>, _>>()?;
369            let array = UnionArray::try_new(fields.clone(), type_ids, None, children)?;
370            Ok(Arc::new(array))
371        }
372        DataType::Union(fields, UnionMode::Dense) => {
373            let values = values.as_any().downcast_ref::<UnionArray>().unwrap();
374
375            let (type_ids, _) = take_union_type_ids(fields, values.type_ids(), indices)?;
376            let type_ids = PrimitiveArray::<Int8Type>::try_new(type_ids, None)?;
377            // Keep index nulls so `take` of each child writes a null instead of
378            // reading child offset 0 (the default `take_native` fills in).
379            let offsets = <PrimitiveArray<Int32Type>>::try_new(
380                take_native::<_, _, VALIDATE_INDICES>(values.offsets().unwrap(), indices),
381                indices.nulls().cloned(),
382            )?;
383
384            let children = fields.iter()
385                .map(|(field_type_id, _)| {
386                    let mask = BooleanArray::from_unary(&type_ids, |value_type_id| value_type_id == field_type_id);
387
388                    let indices = crate::filter::filter(&offsets, &mask)?;
389
390                    let values = values.child(field_type_id);
391
392                    take_impl::<_, VALIDATE_INDICES>(values, indices.as_primitive::<Int32Type>())
393                })
394                .collect::<Result<_, _>>()?;
395
396            let mut child_offsets = [0; 128];
397
398            let offsets = type_ids.values()
399                .iter()
400                .map(|&i| {
401                    let offset = child_offsets[i as usize];
402
403                    child_offsets[i as usize] += 1;
404
405                    offset
406                })
407                .collect();
408
409            let (_, type_ids, _) = type_ids.into_parts();
410
411            let array = UnionArray::try_new(fields.clone(), type_ids, Some(offsets), children)?;
412
413            Ok(Arc::new(array))
414        }
415        t => unimplemented!("Take not supported for data type {:?}", t)
416    }
417}
418
419/// Takes union type ids, substituting a child that can represent a null for
420/// null take indices.
421///
422/// Union arrays do not have a top-level null bitmap. A null is represented by
423/// selecting a child that can store a null value. In particular, a null index
424/// cannot fall back to type id `0`, as unions are not required to have such a
425/// child.
426///
427/// Returns the taken type ids and, when `indices` contains nulls, the type id
428/// used to represent those nulls.
429fn take_union_type_ids<IndexType: ArrowPrimitiveType>(
430    fields: &UnionFields,
431    type_ids: &ScalarBuffer<i8>,
432    indices: &PrimitiveArray<IndexType>,
433) -> Result<(ScalarBuffer<i8>, Option<i8>), ArrowError> {
434    if indices.null_count() == 0 {
435        return Ok((take_native::<_, _, true>(type_ids, indices), None));
436    }
437
438    let null_type_id = union_null_type_id(fields)?;
439    let taken_type_ids = take_native::<_, _, true>(type_ids, indices);
440    let type_ids = indices
441        .iter()
442        .zip(&taken_type_ids)
443        .map(|(index, &type_id)| {
444            if index.is_some() {
445                type_id
446            } else {
447                null_type_id
448            }
449        })
450        .collect::<ScalarBuffer<_>>();
451    Ok((type_ids, Some(null_type_id)))
452}
453
454/// Type id of a union child that can represent a newly introduced null.
455fn union_null_type_id(fields: &UnionFields) -> Result<i8, ArrowError> {
456    fields
457        .iter()
458        .find_map(|(type_id, field)| field_can_represent_take_null(field).then_some(type_id))
459        .ok_or_else(|| {
460            ArrowError::ComputeError(
461                "Cannot take null indices from a union with no field that can represent nulls"
462                    .into(),
463            )
464        })
465}
466
467/// Whether `field` can physically store a newly introduced null.
468///
469/// Union and RunEndEncoded have no top-level validity bitmap, so a null must
470/// be represented by a descendant that is marked nullable. A field marked
471/// nullable is not sufficient if its nested type cannot store a null.
472fn field_can_represent_take_null(field: &FieldRef) -> bool {
473    if !field.is_nullable() {
474        return false;
475    }
476    match field.data_type() {
477        DataType::RunEndEncoded(_, values) => field_can_represent_take_null(values),
478        DataType::Union(fields, _) => fields
479            .iter()
480            .any(|(_, child)| field_can_represent_take_null(child)),
481        _ => true,
482    }
483}
484
485/// Takes a sparse union child for `indices`.
486///
487/// Null take indices select one child that can represent a null
488/// ([`take_union_type_ids`]). Values in the other children at those positions
489/// are unspecified, so they are taken with dummy indices instead of introducing
490/// nulls that would contradict field metadata.
491fn take_sparse_union_child<IndexType: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
492    values: &dyn Array,
493    represent_nulls: bool,
494    indices: &PrimitiveArray<IndexType>,
495) -> Result<ArrayRef, ArrowError> {
496    if represent_nulls || indices.null_count() == 0 {
497        return take_impl::<_, VALIDATE_INDICES>(values, indices);
498    }
499
500    if values.is_empty() {
501        // Dummy index 0 is OOB on an empty child. Sparse children have the same
502        // length as the union, so a non-null index is also OOB and already
503        // panics in `take_native` via [`take_union_type_ids`].
504        return Ok(make_array(
505            new_null_array(values.data_type(), indices.len())
506                .to_data()
507                .into_builder()
508                .nulls(None)
509                .build()?,
510        ));
511    }
512
513    take_impl::<_, VALIDATE_INDICES>(values, &indices_without_nulls(indices))
514}
515
516/// Replaces null take indices with `0` and drops the null bitmap.
517fn indices_without_nulls<IndexType: ArrowPrimitiveType>(
518    indices: &PrimitiveArray<IndexType>,
519) -> PrimitiveArray<IndexType> {
520    let dummy = IndexType::Native::ZERO;
521    let normalized = indices.iter().map(|idx| idx.unwrap_or(dummy));
522    PrimitiveArray::from_iter_values(normalized)
523}
524
525/// Options that define how `take` should behave
526#[derive(Clone, Debug, Default)]
527pub struct TakeOptions {
528    /// Perform bounds check before taking indices from values.
529    /// If enabled, an `ArrowError` is returned if the indices are out of bounds.
530    /// If not enabled, and indices exceed bounds, the kernel will panic.
531    pub check_bounds: bool,
532}
533
534/// `take` implementation for all primitive arrays
535///
536/// This checks if an `indices` slot is populated, and gets the value from `values`
537///  as the populated index.
538/// If the `indices` slot is null, a null value is returned.
539/// For example, given:
540///     values:  [1, 2, 3, null, 5]
541///     indices: [0, null, 4, 3]
542/// The result is: [1 (slot 0), null (null slot), 5 (slot 4), null (slot 3)]
543fn take_primitive<T, I, const VALIDATE_INDICES: bool>(
544    values: &PrimitiveArray<T>,
545    indices: &PrimitiveArray<I>,
546) -> Result<PrimitiveArray<T>, ArrowError>
547where
548    T: ArrowPrimitiveType,
549    I: ArrowPrimitiveType,
550{
551    let values_buf = take_native::<_, _, VALIDATE_INDICES>(values.values(), indices);
552    let nulls = take_nulls::<_, VALIDATE_INDICES>(values.nulls(), indices);
553    Ok(PrimitiveArray::try_new(values_buf, nulls)?.with_data_type(values.data_type().clone()))
554}
555
556#[inline(never)]
557fn take_nulls<I: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
558    values: Option<&NullBuffer>,
559    indices: &PrimitiveArray<I>,
560) -> Option<NullBuffer> {
561    match values.filter(|n| n.null_count() > 0) {
562        Some(n) => NullBuffer::from_unsliced_buffer(
563            take_bits::<_, VALIDATE_INDICES>(n.inner(), indices).into_inner(),
564            indices.len(),
565        ),
566        None => indices.nulls().cloned(),
567    }
568}
569
570#[inline(never)]
571fn take_native<T: ArrowNativeType, I: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
572    values: &[T],
573    indices: &PrimitiveArray<I>,
574) -> ScalarBuffer<T> {
575    match indices.nulls().filter(|n| n.null_count() > 0) {
576        Some(n) => indices
577            .values()
578            .iter()
579            .enumerate()
580            .map(|(idx, index)| match values.get(index.as_usize()) {
581                Some(v) => *v,
582                // SAFETY: idx<indices.len()
583                None => match unsafe { n.inner().value_unchecked(idx) } {
584                    false => T::default(),
585                    true => panic!("Out-of-bounds index {index:?}"),
586                },
587            })
588            .collect(),
589        None => {
590            if VALIDATE_INDICES {
591                indices
592                    .values()
593                    .iter()
594                    .map(|index| values[index.as_usize()])
595                    .collect()
596            } else {
597                indices
598                    .values()
599                    .iter()
600                    .map(|index| {
601                        // SAFETY: caller guarantees all indices are in-bounds.
602                        unsafe { *values.get_unchecked(index.as_usize()) }
603                    })
604                    .collect()
605            }
606        }
607    }
608}
609
610/// Read the bit at `src_bit_idx` from `src` and, if it is set, write a `1` to `dst_bit_idx`
611/// in `dst`. Leaves `dst_bit_idx` unchanged (zero) when the source bit is unset.
612///
613/// ```text
614/// src = 0b00100000  (bit 5 is set)
615/// copy_bit_if_set(src, 5, dst, 2)  →  dst bit 2 becomes 1
616/// ```
617///
618/// # Safety
619/// - `src` must be valid for reads up to byte `src_bit_idx / 8`.
620/// - `dst` must be valid for writes up to byte `dst_bit_idx / 8`.
621#[inline(always)]
622unsafe fn copy_bit_if_set(src: *const u8, src_bit_idx: usize, dst: *mut u8, dst_bit_idx: usize) {
623    unsafe {
624        if bit_util::get_bit_raw(src, src_bit_idx) {
625            bit_util::set_bit_raw(dst, dst_bit_idx);
626        }
627    }
628}
629
630/// Read the bit at `bit_idx` from `src` and return it shifted to `out_pos`, ready to be
631/// OR'd into an output byte accumulator.
632///
633/// ```text
634/// src = 0b10100000  (bit 5 is set)
635/// pack_bit(src, 5, 2)  →  0b00000100   (bit from position 5, placed at position 2)
636/// ```
637///
638/// # Safety
639/// `src` must be valid for reads up to byte `bit_idx / 8`.
640#[inline(always)]
641unsafe fn pack_bit(src: *const u8, bit_idx: usize, out_pos: usize) -> u8 {
642    let byte = unsafe { *src.add(bit_idx >> 3) }; // byte containing bit `bit_idx`
643    ((byte >> (bit_idx & 7)) & 1) << out_pos // extract the bit, shift to output position
644}
645
646#[inline(never)]
647fn take_bits<I: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
648    values: &BooleanBuffer,
649    indices: &PrimitiveArray<I>,
650) -> BooleanBuffer {
651    let len = indices.len();
652    let src_offset = values.offset();
653    let src_ptr = values.values().as_ptr();
654    let out_bytes = len.div_ceil(8);
655
656    match indices.nulls().filter(|nulls| nulls.null_count() > 0) {
657        Some(index_nulls) => {
658            let mut output = vec![0u8; out_bytes];
659            let out_ptr = output.as_mut_ptr();
660            index_nulls.valid_indices().for_each(|valid_idx| {
661                // SAFETY: valid_idx < indices.len(), guaranteed by valid_indices().
662                let index_val = unsafe { indices.value_unchecked(valid_idx) }.as_usize();
663                if VALIDATE_INDICES {
664                    if values.value(index_val) {
665                        // SAFETY: valid_idx < indices.len() = len, output buffer holds len bits.
666                        unsafe { bit_util::set_bit_raw(out_ptr, valid_idx) };
667                    }
668                } else {
669                    // SAFETY: caller guarantees index_val < values.len().
670                    unsafe { copy_bit_if_set(src_ptr, index_val + src_offset, out_ptr, valid_idx) };
671                }
672            });
673            BooleanBuffer::new(Buffer::from(output), 0, len)
674        }
675        None => {
676            // Build the output byte-by-byte with an 8-element inner loop so the
677            // compiler can fully unroll it and issue the 8 source loads in parallel.
678            let mut output = vec![0u8; out_bytes];
679            let out_slice = output.as_mut_slice();
680            let full_bytes = len / 8;
681
682            for (byte_idx, out_byte) in out_slice.iter_mut().enumerate().take(full_bytes) {
683                let base = byte_idx * 8;
684                let mut byte = 0u8;
685                for bit in 0..8usize {
686                    // SAFETY: base + bit < full_bytes * 8 <= len, so base + bit is a valid
687                    // position in the indices array.
688                    let index_val = unsafe { indices.value_unchecked(base + bit) }.as_usize();
689                    if VALIDATE_INDICES {
690                        byte |= (values.value(index_val) as u8) << bit;
691                    } else {
692                        // SAFETY: caller guarantees index_val < values.len().
693                        byte |= unsafe { pack_bit(src_ptr, index_val + src_offset, bit) };
694                    }
695                }
696                *out_byte = byte;
697            }
698            // Handle remaining bits when len is not a multiple of 8.
699            if full_bytes < out_bytes {
700                let base = full_bytes * 8;
701                let mut byte = 0u8;
702                for bit in 0..(len - base) {
703                    // SAFETY: base + bit < len (remainder loop bound), so base + bit is a
704                    // valid position in the indices array.
705                    let index_val = unsafe { indices.value_unchecked(base + bit) }.as_usize();
706                    if VALIDATE_INDICES {
707                        byte |= (values.value(index_val) as u8) << bit;
708                    } else {
709                        // SAFETY: caller guarantees index_val < values.len().
710                        byte |= unsafe { pack_bit(src_ptr, index_val + src_offset, bit) };
711                    }
712                }
713                out_slice[full_bytes] = byte;
714            }
715            BooleanBuffer::new(Buffer::from(output), 0, len)
716        }
717    }
718}
719
720/// Gather value bits and validity bits from two boolean buffers in a single pass.
721/// Used when the values array itself has nulls, avoiding two separate `take_bits` calls.
722#[inline(never)]
723fn take_bits_with_validity<I: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
724    values: &BooleanBuffer,
725    validity: &BooleanBuffer,
726    indices: &PrimitiveArray<I>,
727) -> (BooleanBuffer, Option<NullBuffer>) {
728    let len = indices.len();
729    let value_bit_offset = values.offset();
730    let validity_bit_offset = validity.offset();
731    let value_data_ptr = values.values().as_ptr();
732    let validity_data_ptr = validity.values().as_ptr();
733    let out_bytes = len.div_ceil(8);
734
735    let mut value_out = vec![0u8; out_bytes];
736    let mut validity_out = vec![0u8; out_bytes];
737
738    match indices.nulls().filter(|nulls| nulls.null_count() > 0) {
739        Some(index_nulls) => {
740            let value_out_ptr = value_out.as_mut_ptr();
741            let validity_out_ptr = validity_out.as_mut_ptr();
742            for out_pos in index_nulls.valid_indices() {
743                // SAFETY: out_pos < indices.len(), guaranteed by valid_indices().
744                let src_idx = unsafe { indices.value_unchecked(out_pos) }.as_usize();
745                if VALIDATE_INDICES {
746                    if values.value(src_idx) {
747                        // SAFETY: out_pos < indices.len() = len, output buffer holds len bits.
748                        unsafe { bit_util::set_bit_raw(value_out_ptr, out_pos) };
749                    }
750                    if validity.value(src_idx) {
751                        // SAFETY: out_pos < indices.len() = len, output buffer holds len bits.
752                        unsafe { bit_util::set_bit_raw(validity_out_ptr, out_pos) };
753                    }
754                } else {
755                    // SAFETY: caller guarantees src_idx < values.len().
756                    unsafe {
757                        copy_bit_if_set(
758                            value_data_ptr,
759                            src_idx + value_bit_offset,
760                            value_out_ptr,
761                            out_pos,
762                        );
763                        copy_bit_if_set(
764                            validity_data_ptr,
765                            src_idx + validity_bit_offset,
766                            validity_out_ptr,
767                            out_pos,
768                        );
769                    }
770                }
771            }
772        }
773        None => {
774            let value_out_slice = value_out.as_mut_slice();
775            let validity_out_slice = validity_out.as_mut_slice();
776            let full_bytes = len / 8;
777
778            for (byte_idx, (value_out_byte, validity_out_byte)) in value_out_slice
779                .iter_mut()
780                .zip(validity_out_slice.iter_mut())
781                .enumerate()
782                .take(full_bytes)
783            {
784                let bit_base = byte_idx * 8;
785                let mut packed_values = 0u8;
786                let mut packed_validity = 0u8;
787                for bit_pos in 0..8usize {
788                    // SAFETY: bit_base + bit_pos < full_bytes * 8 <= len.
789                    let src_idx = unsafe { indices.value_unchecked(bit_base + bit_pos) }.as_usize();
790                    if VALIDATE_INDICES {
791                        packed_values |= (values.value(src_idx) as u8) << bit_pos;
792                        packed_validity |= (validity.value(src_idx) as u8) << bit_pos;
793                    } else {
794                        // SAFETY: caller guarantees src_idx < values.len().
795                        packed_values |= unsafe {
796                            pack_bit(value_data_ptr, src_idx + value_bit_offset, bit_pos)
797                        };
798                        packed_validity |= unsafe {
799                            pack_bit(validity_data_ptr, src_idx + validity_bit_offset, bit_pos)
800                        };
801                    }
802                }
803                *value_out_byte = packed_values;
804                *validity_out_byte = packed_validity;
805            }
806            // Handle remaining bits when len is not a multiple of 8.
807            if full_bytes < out_bytes {
808                let bit_base = full_bytes * 8;
809                let mut packed_values = 0u8;
810                let mut packed_validity = 0u8;
811                for bit_pos in 0..(len - bit_base) {
812                    // SAFETY: bit_base + bit_pos < len (remainder loop bound).
813                    let src_idx = unsafe { indices.value_unchecked(bit_base + bit_pos) }.as_usize();
814                    if VALIDATE_INDICES {
815                        packed_values |= (values.value(src_idx) as u8) << bit_pos;
816                        packed_validity |= (validity.value(src_idx) as u8) << bit_pos;
817                    } else {
818                        // SAFETY: caller guarantees src_idx < values.len().
819                        packed_values |= unsafe {
820                            pack_bit(value_data_ptr, src_idx + value_bit_offset, bit_pos)
821                        };
822                        packed_validity |= unsafe {
823                            pack_bit(validity_data_ptr, src_idx + validity_bit_offset, bit_pos)
824                        };
825                    }
826                }
827                value_out_slice[full_bytes] = packed_values;
828                validity_out_slice[full_bytes] = packed_validity;
829            }
830        }
831    }
832
833    let value_buf_out = BooleanBuffer::new(Buffer::from(value_out), 0, len);
834    let validity_buf_out = NullBuffer::from_unsliced_buffer(validity_out, len);
835    (value_buf_out, validity_buf_out)
836}
837
838/// `take` implementation for boolean arrays
839fn take_boolean<IndexType: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
840    array: &BooleanArray,
841    indices: &PrimitiveArray<IndexType>,
842) -> BooleanArray {
843    let bits = array.values();
844    match array.nulls().filter(|n| n.null_count() > 0) {
845        Some(array_nulls) => {
846            let (val_buf, null_buf) =
847                take_bits_with_validity::<_, VALIDATE_INDICES>(bits, array_nulls.inner(), indices);
848            BooleanArray::new(val_buf, null_buf)
849        }
850        None => {
851            let val_buf = take_bits::<_, VALIDATE_INDICES>(bits, indices);
852            let null_buf = take_nulls::<_, VALIDATE_INDICES>(None, indices);
853            BooleanArray::new(val_buf, null_buf)
854        }
855    }
856}
857
858/// `take` implementation for string arrays
859fn take_bytes<T: ByteArrayType, IndexType: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
860    array: &GenericByteArray<T>,
861    indices: &PrimitiveArray<IndexType>,
862) -> Result<GenericByteArray<T>, ArrowError> {
863    let mut values: Vec<u8> = Vec::new();
864    let mut offsets = Vec::with_capacity(indices.len() + 1);
865    offsets.push(T::Offset::default());
866
867    let input_offsets = array.value_offsets();
868    let mut capacity = 0;
869    let nulls = take_nulls::<_, VALIDATE_INDICES>(array.nulls(), indices);
870
871    // Branch on output nulls — `None` means every output slot is valid.
872    match nulls.as_ref().filter(|n| n.null_count() > 0) {
873        // Fast path: no nulls in output, every index is valid.
874        None => {
875            for index in indices.values() {
876                let index = index.as_usize();
877                let start = input_offsets[index].as_usize();
878                let end = input_offsets[index + 1].as_usize();
879                capacity += end - start;
880                offsets.push(
881                    T::Offset::from_usize(capacity)
882                        .ok_or_else(|| ArrowError::OffsetOverflowError(capacity))?,
883                );
884            }
885
886            values.reserve(capacity);
887
888            let dst = values.spare_capacity_mut();
889            debug_assert!(dst.len() >= capacity);
890            let mut offset = 0;
891
892            for index in indices.values() {
893                // SAFETY: in-bounds proven by the first loop's bounds-checked offset access.
894                // dst asserted above to include the required capacity.
895                unsafe {
896                    let data: &[u8] = array.value_unchecked(index.as_usize()).as_ref();
897                    std::ptr::copy_nonoverlapping(
898                        data.as_ptr(),
899                        dst.get_unchecked_mut(offset..).as_mut_ptr().cast::<u8>(),
900                        data.len(),
901                    );
902                    offset += data.len();
903                }
904            }
905
906            // SAFETY: wrote exactly `capacity` bytes above; reserved on line above.
907            unsafe {
908                values.set_len(capacity);
909            }
910        }
911        // Nullable path: only process valid (non-null) output positions.
912        Some(output_nulls) => {
913            let mut source_ranges = Vec::with_capacity(indices.len() - output_nulls.null_count());
914            let mut last_filled = 0;
915
916            // Pre-fill offsets; we overwrite valid positions below.
917            offsets.resize(indices.len() + 1, T::Offset::default());
918
919            // Pass 1: find all valid ranges that need to be copied.
920            for i in output_nulls.valid_indices() {
921                let current_offset = T::Offset::from_usize(capacity)
922                    .ok_or_else(|| ArrowError::OffsetOverflowError(capacity))?;
923                // Fill offsets for skipped null slots so they get zero-length ranges.
924                if last_filled < i {
925                    offsets[last_filled + 1..=i].fill(current_offset);
926                }
927
928                // SAFETY: `i` comes from a validity bitmap over `indices`, so it is in-bounds.
929                let index = unsafe { indices.value_unchecked(i) }.as_usize();
930                let start = input_offsets[index].as_usize();
931                let end = input_offsets[index + 1].as_usize();
932                capacity += end - start;
933                offsets[i + 1] = T::Offset::from_usize(capacity)
934                    .ok_or_else(|| ArrowError::OffsetOverflowError(capacity))?;
935
936                source_ranges.push((start, end));
937                last_filled = i + 1;
938            }
939
940            // Fill trailing null offsets after the last valid position.
941            let final_offset = T::Offset::from_usize(capacity)
942                .ok_or_else(|| ArrowError::OffsetOverflowError(capacity))?;
943            offsets[last_filled + 1..].fill(final_offset);
944            // Pass 2: copy byte data for all collected ranges.
945            values.reserve(capacity);
946            debug_assert_eq!(
947                source_ranges.iter().map(|(s, e)| e - s).sum::<usize>(),
948                capacity,
949                "capacity must equal total bytes across all ranges"
950            );
951
952            let src = array.value_data();
953            let src = src.as_ptr();
954            let dst = values.spare_capacity_mut();
955            debug_assert!(dst.len() >= capacity);
956
957            let mut offset = 0;
958
959            for (start, end) in source_ranges {
960                let value_len = end - start;
961                // SAFETY: caller guarantees each (start, end) is in-bounds of `src`.
962                // `dst` asserted above to include the required capacity.
963                // The regions don't overlap (src is input, dst is a fresh allocation).
964                unsafe {
965                    std::ptr::copy_nonoverlapping(
966                        src.add(start),
967                        dst.get_unchecked_mut(offset..).as_mut_ptr().cast::<u8>(),
968                        value_len,
969                    );
970                    offset += value_len;
971                }
972            }
973            // SAFETY: caller guarantees `capacity` == total bytes across all ranges,
974            // so the loop above wrote exactly `capacity` bytes.
975            unsafe { values.set_len(capacity) };
976        }
977    }
978
979    // SAFETY: offsets are monotonically increasing and in-bounds of `values`,
980    // and `nulls` (if present) has length == `indices.len()`.
981    let array = unsafe {
982        let offsets = OffsetBuffer::new_unchecked(offsets.into());
983        GenericByteArray::<T>::new_unchecked(offsets, values.into(), nulls)
984    };
985
986    Ok(array)
987}
988
989/// `take` implementation for byte view arrays
990fn take_byte_view<T: ByteViewType, IndexType: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
991    array: &GenericByteViewArray<T>,
992    indices: &PrimitiveArray<IndexType>,
993) -> Result<GenericByteViewArray<T>, ArrowError> {
994    let new_views = take_native::<_, _, VALIDATE_INDICES>(array.views(), indices);
995    let new_nulls = take_nulls::<_, VALIDATE_INDICES>(array.nulls(), indices);
996    let buffers = Arc::clone(array.data_buffers());
997    // Safety:  array.views was valid, and take_native copies only valid values, and verifies bounds
998    Ok(unsafe { GenericByteViewArray::new_unchecked(new_views, buffers, new_nulls) })
999}
1000
1001/// `take` implementation for list arrays
1002///
1003/// Copies the selected list entries' child slices into a new child array
1004/// via `MutableArrayData`, then reconstructs a list array with new offsets
1005fn take_list<IndexType, OffsetType, const VALIDATE_INDICES: bool>(
1006    values: &GenericListArray<OffsetType::Native>,
1007    indices: &PrimitiveArray<IndexType>,
1008) -> Result<GenericListArray<OffsetType::Native>, ArrowError>
1009where
1010    IndexType: ArrowPrimitiveType,
1011    OffsetType: ArrowPrimitiveType,
1012    OffsetType::Native: OffsetSizeTrait,
1013    PrimitiveArray<OffsetType>: From<Vec<OffsetType::Native>>,
1014{
1015    let src_offsets = values.value_offsets();
1016    let child_data = values.values().to_data();
1017    // The number of child values that the rows use, excluding values outside a slice
1018    let visible_child_len = (values.offsets().last() - values.offsets().first()).as_usize();
1019    // An estimate of the output's child length, from the average length of the rows
1020    let estimated_child_len = visible_child_len
1021        .checked_div(values.len())
1022        .map_or(0, |avg| avg.saturating_mul(indices.len()));
1023    let nulls = take_nulls::<_, VALIDATE_INDICES>(values.nulls(), indices);
1024
1025    let mut dst_offsets = Vec::with_capacity(indices.len() + 1);
1026    dst_offsets.push(OffsetType::Native::zero());
1027
1028    let field = values.value_field().clone();
1029
1030    if child_data.null_count() == 0
1031        && let Some(bytes_per_value) = child_data.data_type().primitive_width()
1032    {
1033        let values_buf = &child_data.buffers()[0];
1034        let child_buf_offset = child_data.offset() * bytes_per_value;
1035
1036        let capacity = estimated_child_len.saturating_mul(bytes_per_value);
1037        let mut dst_buf = MutableBuffer::try_with_capacity(capacity)
1038            .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
1039
1040        let mut child_len = OffsetType::Native::zero();
1041
1042        match nulls.as_ref().filter(|n| n.null_count() > 0) {
1043            None => {
1044                for &idx in indices.values() {
1045                    let row = idx.as_usize();
1046                    let start = child_buf_offset + src_offsets[row].as_usize() * bytes_per_value;
1047                    let end = child_buf_offset + src_offsets[row + 1].as_usize() * bytes_per_value;
1048                    dst_buf
1049                        .try_extend_from_slice(&values_buf[start..end])
1050                        .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
1051                    child_len = child_len
1052                        .checked_add(&(src_offsets[row + 1] - src_offsets[row]))
1053                        .ok_or_else(|| ArrowError::OffsetOverflowError(child_len.as_usize()))?;
1054                    dst_offsets.push(child_len);
1055                }
1056            }
1057            Some(valid) => {
1058                let mut prev = 0;
1059                for vidx in valid.valid_indices() {
1060                    // Fill offsets for null values between the two valid indices.
1061                    if prev < vidx {
1062                        dst_offsets.extend(std::iter::repeat_n(child_len, vidx - prev));
1063                    }
1064                    // SAFETY: vidx < indices.len(), guaranteed by valid_indices().
1065                    let row = unsafe { indices.value_unchecked(vidx) }.as_usize();
1066                    let (start, end) = if VALIDATE_INDICES {
1067                        (
1068                            child_buf_offset + src_offsets[row].as_usize() * bytes_per_value,
1069                            child_buf_offset + src_offsets[row + 1].as_usize() * bytes_per_value,
1070                        )
1071                    } else {
1072                        // SAFETY: caller guarantees row < values.len(), so row+1 is also in bounds.
1073                        unsafe {
1074                            (
1075                                child_buf_offset
1076                                    + src_offsets.get_unchecked(row).as_usize() * bytes_per_value,
1077                                child_buf_offset
1078                                    + src_offsets.get_unchecked(row + 1).as_usize()
1079                                        * bytes_per_value,
1080                            )
1081                        }
1082                    };
1083                    dst_buf
1084                        .try_extend_from_slice(&values_buf[start..end])
1085                        .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
1086                    child_len = child_len
1087                        .checked_add(&(src_offsets[row + 1] - src_offsets[row]))
1088                        .ok_or_else(|| ArrowError::OffsetOverflowError(child_len.as_usize()))?;
1089                    dst_offsets.push(child_len);
1090                    prev = vidx + 1;
1091                }
1092                dst_offsets.extend(std::iter::repeat_n(child_len, indices.len() - prev));
1093            }
1094        }
1095
1096        debug_assert_eq!(
1097            dst_offsets.len(),
1098            indices.len() + 1,
1099            "New offsets was filled under/over the expected capacity"
1100        );
1101
1102        // Safety: data_type, len, and buffer are all derived from the already-validated
1103        // source child_data, so re-validation is unnecessary.
1104        let child = make_array(unsafe {
1105            ArrayData::builder(child_data.data_type().clone())
1106                .len(child_len.as_usize())
1107                .add_buffer(dst_buf.into())
1108                .build_unchecked()
1109        });
1110        // SAFETY: `dst_offsets` is constructed to be monotonically increasing above.
1111        let offsets = unsafe { OffsetBuffer::new_unchecked(ScalarBuffer::from(dst_offsets)) };
1112        return GenericListArray::<OffsetType::Native>::try_new(field, offsets, child, nulls);
1113    }
1114
1115    let mut mutable = MutableArrayData::try_new(
1116        vec![&child_data],
1117        child_data.null_count() > 0,
1118        estimated_child_len,
1119    )?;
1120
1121    match nulls.as_ref().filter(|n| n.null_count() > 0) {
1122        None => {
1123            for idx in indices.values() {
1124                let row = idx.as_usize();
1125                mutable.try_extend(
1126                    0,
1127                    src_offsets[row].as_usize(),
1128                    src_offsets[row + 1].as_usize(),
1129                )?;
1130                dst_offsets.push(
1131                    OffsetType::Native::from_usize(mutable.len())
1132                        .ok_or_else(|| ArrowError::OffsetOverflowError(mutable.len()))?,
1133                );
1134            }
1135        }
1136        Some(valid) => {
1137            let mut last = 0;
1138            for i in valid.valid_indices() {
1139                let current = OffsetType::Native::from_usize(mutable.len())
1140                    .ok_or_else(|| ArrowError::OffsetOverflowError(mutable.len()))?;
1141                if last < i {
1142                    dst_offsets.extend(std::iter::repeat_n(current, i - last));
1143                }
1144                // SAFETY: i < indices.len(), guaranteed by valid_indices().
1145                let row = unsafe { indices.value_unchecked(i) }.as_usize();
1146                let (start, end) = if VALIDATE_INDICES {
1147                    (src_offsets[row].as_usize(), src_offsets[row + 1].as_usize())
1148                } else {
1149                    // SAFETY: caller guarantees row < values.len(), so row+1 is also in bounds.
1150                    unsafe {
1151                        (
1152                            src_offsets.get_unchecked(row).as_usize(),
1153                            src_offsets.get_unchecked(row + 1).as_usize(),
1154                        )
1155                    }
1156                };
1157                mutable.try_extend(0, start, end)?;
1158                dst_offsets.push(
1159                    OffsetType::Native::from_usize(mutable.len())
1160                        .ok_or_else(|| ArrowError::OffsetOverflowError(mutable.len()))?,
1161                );
1162                last = i + 1;
1163            }
1164            // Filling offsets for null values at the end
1165            let final_offset = OffsetType::Native::from_usize(mutable.len())
1166                .ok_or_else(|| ArrowError::OffsetOverflowError(mutable.len()))?;
1167            dst_offsets.extend(std::iter::repeat_n(final_offset, indices.len() - last));
1168        }
1169    }
1170
1171    debug_assert_eq!(dst_offsets.len(), indices.len() + 1);
1172
1173    // SAFETY: `dst_offsets` is constructed to be monotonically increasing above
1174    let offsets = unsafe { OffsetBuffer::new_unchecked(ScalarBuffer::from(dst_offsets)) };
1175    let child = make_array(mutable.freeze());
1176    GenericListArray::<OffsetType::Native>::try_new(field, offsets, child, nulls)
1177}
1178
1179fn take_list_view<IndexType, OffsetType, const VALIDATE_INDICES: bool>(
1180    values: &GenericListViewArray<OffsetType::Native>,
1181    indices: &PrimitiveArray<IndexType>,
1182) -> Result<GenericListViewArray<OffsetType::Native>, ArrowError>
1183where
1184    IndexType: ArrowPrimitiveType,
1185    OffsetType: ArrowPrimitiveType,
1186    OffsetType::Native: OffsetSizeTrait,
1187{
1188    let taken_offsets = take_native::<_, _, VALIDATE_INDICES>(values.offsets(), indices);
1189    let taken_sizes = take_native::<_, _, VALIDATE_INDICES>(values.sizes(), indices);
1190    let nulls = take_nulls::<_, VALIDATE_INDICES>(values.nulls(), indices);
1191
1192    let field = match values.data_type() {
1193        DataType::ListView(field) | DataType::LargeListView(field) => field.clone(),
1194        d => unreachable!("take_list_view called with non-list-view data type {d}"),
1195    };
1196
1197    // SAFETY: the taken offsets/sizes are a permutation of the (valid) input
1198    // offsets/sizes, so they remain within the bounds of the child array.
1199    Ok(unsafe {
1200        GenericListViewArray::<OffsetType::Native>::new_unchecked(
1201            field,
1202            taken_offsets,
1203            taken_sizes,
1204            Arc::clone(values.values()),
1205            nulls,
1206        )
1207    })
1208}
1209
1210/// `take` implementation for `FixedSizeListArray`
1211///
1212/// Calculates the index and indexed offset for the inner array,
1213/// applying `take` on the inner array, then reconstructing a list array
1214/// with the indexed offsets
1215fn take_fixed_size_list<IndexType: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
1216    values: &FixedSizeListArray,
1217    indices: &PrimitiveArray<IndexType>,
1218    length: <UInt32Type as ArrowPrimitiveType>::Native,
1219) -> Result<FixedSizeListArray, ArrowError> {
1220    let field = values.value_field();
1221    let child = values.values();
1222    let nulls = take_nulls::<_, VALIDATE_INDICES>(values.nulls(), indices);
1223
1224    // Fast path: primitive child with no nulls  copy row-sized byte blocks directly,
1225    let taken_child = if child.null_count() == 0
1226        && let Some(element_size) = child.data_type().primitive_width()
1227    {
1228        take_fixed_size_list_primitive(
1229            child,
1230            indices,
1231            length as usize,
1232            element_size,
1233            nulls.as_ref(),
1234        )?
1235    } else {
1236        let list_indices = take_value_indices_from_fixed_size_list(values, indices, length)?;
1237        take_impl::<UInt32Type, VALIDATE_INDICES>(child.as_ref(), &list_indices)?
1238    };
1239
1240    FixedSizeListArray::try_new_with_length(
1241        field.clone(),
1242        length as i32,
1243        taken_child,
1244        nulls,
1245        indices.len(),
1246    )
1247}
1248
1249#[inline(never)]
1250fn take_fixed_size_list_primitive<IndexType: ArrowPrimitiveType>(
1251    child: &ArrayRef,
1252    indices: &PrimitiveArray<IndexType>,
1253    list_size: usize,
1254    element_size: usize,
1255    taken_row_nulls: Option<&NullBuffer>,
1256) -> Result<ArrayRef, ArrowError> {
1257    let row_bytes = list_size
1258        .checked_mul(element_size)
1259        .ok_or_else(|| ArrowError::MemoryError("take output size overflow".into()))?;
1260    let child_data = child.to_data();
1261    let src = child_data.buffers()[0].as_slice();
1262    let child_byte_offset = child_data.offset() * element_size;
1263
1264    let out_len = indices
1265        .len()
1266        .checked_mul(list_size)
1267        .ok_or_else(|| ArrowError::MemoryError("take output size overflow".into()))?;
1268    let out_byte_len = indices
1269        .len()
1270        .checked_mul(row_bytes)
1271        .ok_or_else(|| ArrowError::MemoryError("take output size overflow".into()))?;
1272
1273    let mut out = MutableBuffer::try_from_len_zeroed(out_byte_len)
1274        .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
1275    let out_slice = out.as_slice_mut();
1276
1277    if indices.null_count() == 0 {
1278        for (out_row, index) in indices.values().iter().enumerate() {
1279            let src_start = child_byte_offset + index.as_usize() * row_bytes;
1280            out_slice[out_row * row_bytes..(out_row + 1) * row_bytes]
1281                .copy_from_slice(&src[src_start..src_start + row_bytes]);
1282        }
1283    } else {
1284        for (out_row, index) in indices.values().iter().enumerate() {
1285            if indices.is_valid(out_row) {
1286                let src_start = child_byte_offset + index.as_usize() * row_bytes;
1287                out_slice[out_row * row_bytes..(out_row + 1) * row_bytes]
1288                    .copy_from_slice(&src[src_start..src_start + row_bytes]);
1289            }
1290        }
1291    }
1292    // Expand the per-row null bitmap to per-element: each null row produces `list_size` null elements.
1293    let child_null_buf = taken_row_nulls
1294        .map(|n| {
1295            n.try_expand(list_size)
1296                .map(|n| n.buffer().clone())
1297                .map_err(|e| ArrowError::MemoryError(e.to_string()))
1298        })
1299        .transpose()?;
1300
1301    // SAFETY:
1302    // - The data buffer has `indices.len() * row_bytes` bytes = `out_len` elements of a
1303    //   primitive type, matching `.len(out_len)`.
1304    // - The null buffer (when present) is `ceil(out_len, 8)` bytes via
1305    //   `try_expand(list_size).buffer()`.
1306    // - Primitive types have exactly one value buffer.
1307    let array_data = unsafe {
1308        ArrayData::builder(child.data_type().clone())
1309            .len(out_len)
1310            .add_buffer(out.into())
1311            .null_bit_buffer(child_null_buf)
1312            .build_unchecked()
1313    };
1314    Ok(make_array(array_data))
1315}
1316
1317/// The take kernel implementation for `FixedSizeBinaryArray`.
1318///
1319/// The computation is done in two steps:
1320/// - Compute the values buffer
1321/// - Compute the null buffer
1322fn take_fixed_size_binary<IndexType: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
1323    values: &FixedSizeBinaryArray,
1324    indices: &PrimitiveArray<IndexType>,
1325    size: i32,
1326) -> Result<FixedSizeBinaryArray, ArrowError> {
1327    let size_usize = usize::try_from(size).map_err(|_| {
1328        ArrowError::InvalidArgumentError(format!("Cannot convert size '{size}' to usize"))
1329    })?;
1330
1331    let result_buffer = match size_usize {
1332        1 => take_fixed_size::<IndexType, 1>(values.values(), indices),
1333        2 => take_fixed_size::<IndexType, 2>(values.values(), indices),
1334        4 => take_fixed_size::<IndexType, 4>(values.values(), indices),
1335        8 => take_fixed_size::<IndexType, 8>(values.values(), indices),
1336        16 => take_fixed_size::<IndexType, 16>(values.values(), indices),
1337        _ => take_fixed_size_binary_buffer_dynamic_length(values, indices, size_usize),
1338    };
1339
1340    let value_nulls = take_nulls::<_, VALIDATE_INDICES>(values.nulls(), indices);
1341    let final_nulls = NullBuffer::union(value_nulls.as_ref(), indices.nulls());
1342
1343    return FixedSizeBinaryArray::try_new_with_len(size, result_buffer, final_nulls, indices.len());
1344
1345    /// Implementation of the take kernel for fixed size binary arrays.
1346    #[inline(never)]
1347    fn take_fixed_size_binary_buffer_dynamic_length<IndexType: ArrowPrimitiveType>(
1348        values: &FixedSizeBinaryArray,
1349        indices: &PrimitiveArray<IndexType>,
1350        size_usize: usize,
1351    ) -> Buffer {
1352        let values_buffer = values.values().as_slice();
1353        let mut output = Vec::with_capacity(indices.len() * size_usize);
1354
1355        if indices.null_count() == 0 {
1356            let array_iter = indices.values().iter().map(|idx| {
1357                let offset = idx.as_usize() * size_usize;
1358                &values_buffer[offset..offset + size_usize]
1359            });
1360            for slice in array_iter {
1361                output.extend_from_slice(slice);
1362            }
1363        } else {
1364            // The indices nullability cannot be ignored here because the values buffer may contain
1365            // nulls which should not cause a panic.
1366            let array_iter = indices.iter().map(|idx| {
1367                idx.map(|idx| {
1368                    let offset = idx.as_usize() * size_usize;
1369                    &values_buffer[offset..offset + size_usize]
1370                })
1371            });
1372            for slice in array_iter {
1373                match slice {
1374                    None => output.resize(output.len() + size_usize, 0),
1375                    Some(slice) => output.extend_from_slice(slice),
1376                }
1377            }
1378        }
1379
1380        output.into()
1381    }
1382}
1383
1384/// Implements the take kernel semantics over a flat [`Buffer`], interpreting it as a slice of
1385/// `&[[u8; N]]`, where `N` is a compile-time constant. The usage of a flat [`Buffer`] allows using
1386/// this kernel without an available [`ArrowPrimitiveType`] (e.g., for `[u8; 5]`).
1387///
1388/// # Using This Function in the Primitive Take Kernel
1389///
1390/// This function is basically the same as [`take_native`] but just on a flat [`Buffer`] instead of
1391/// the primitive [`ScalarBuffer`]. Ideally, the [`take_primitive`] kernel should just use this
1392/// more general function. However, the "idiomatic code" requires the
1393/// [feature(generic_const_exprs)](https://github.com/rust-lang/rust/issues/76560) for calling
1394/// `take_fixed_size<I, { size_of::<T::Native> () } >(...)`. Once this feature has been stabilized,
1395/// we can use this function also in the primitive kernels.
1396fn take_fixed_size<IndexType: ArrowPrimitiveType, const N: usize>(
1397    buffer: &Buffer,
1398    indices: &PrimitiveArray<IndexType>,
1399) -> Buffer {
1400    assert_eq!(
1401        buffer.len() % N,
1402        0,
1403        "Invalid array length in take_fixed_size"
1404    );
1405
1406    let ptr = buffer.as_ptr();
1407    let chunk_ptr = ptr.cast::<[u8; N]>();
1408    let chunk_len = buffer.len() / N;
1409    let buffer: &[[u8; N]] = unsafe {
1410        // SAFETY: interpret an already valid slice as a slice of N-byte chunks. N divides buffer
1411        // length without remainder.
1412        std::slice::from_raw_parts(chunk_ptr, chunk_len)
1413    };
1414
1415    let result_buffer = match indices.nulls().filter(|n| n.null_count() > 0) {
1416        Some(n) => indices
1417            .values()
1418            .iter()
1419            .enumerate()
1420            .map(|(idx, index)| match buffer.get(index.as_usize()) {
1421                Some(v) => *v,
1422                // SAFETY: idx<indices.len()
1423                None => match unsafe { n.inner().value_unchecked(idx) } {
1424                    false => [0u8; N],
1425                    true => panic!("Out-of-bounds index {index:?}"),
1426                },
1427            })
1428            .collect::<Vec<_>>(),
1429        None => indices
1430            .values()
1431            .iter()
1432            .map(|index| buffer[index.as_usize()])
1433            .collect::<Vec<_>>(),
1434    };
1435
1436    let mut vec = ManuallyDrop::new(result_buffer); // Prevent de-allocation
1437    let ptr = vec.as_mut_ptr();
1438    let len = vec.len();
1439    let cap = vec.capacity();
1440    let result_buffer = unsafe {
1441        // SAFETY: flattening an already valid Vec.
1442        Vec::from_raw_parts(ptr.cast::<u8>(), len * N, cap * N)
1443    };
1444
1445    Buffer::from_vec(result_buffer)
1446}
1447
1448/// `take` implementation for dictionary arrays
1449///
1450/// applies `take` to the keys of the dictionary array and returns a new dictionary array
1451/// with the same dictionary values and reordered keys
1452fn take_dict<T: ArrowDictionaryKeyType, I: ArrowPrimitiveType, const VALIDATE_INDICES: bool>(
1453    values: &DictionaryArray<T>,
1454    indices: &PrimitiveArray<I>,
1455) -> Result<DictionaryArray<T>, ArrowError> {
1456    let new_keys = take_primitive::<_, _, VALIDATE_INDICES>(values.keys(), indices)?;
1457    Ok(unsafe { DictionaryArray::new_unchecked(new_keys, values.values().clone()) })
1458}
1459
1460/// `take` implementation for run arrays
1461///
1462/// Finds physical indices for the given logical indices and builds output run array
1463/// by taking values in the input run_array.values at the physical indices.
1464/// The output run array will be run encoded on the physical indices and not on output values.
1465/// For e.g. an input `RunArray{ run_ends = [2,4,6,8], values=[1,2,1,2] }` and `logical_indices=[2,3,6,7]`
1466/// would be converted to `physical_indices=[1,1,3,3]` which will be used to build
1467/// output `RunArray{ run_ends=[2,4], values=[2,2] }`.
1468///
1469/// A null logical index becomes a null run. Consecutive nulls are merged.
1470fn take_run<T: RunEndIndexType, I: ArrowPrimitiveType>(
1471    run_array: &RunArray<T>,
1472    logical_indices: &PrimitiveArray<I>,
1473) -> Result<RunArray<T>, ArrowError> {
1474    if logical_indices.null_count() > 0 && !run_array.values_field().is_nullable() {
1475        return Err(ArrowError::ComputeError(
1476            "Cannot take null indices from a RunEndEncoded array with a non-nullable values field"
1477                .into(),
1478        ));
1479    }
1480
1481    let physical_indices = physical_indices_for_take(run_array, logical_indices)?;
1482
1483    // Run encode the physical indices into new_run_ends
1484    // Keep track of the physical indices to take in take_value_indices
1485    // `unwrap` is used in this function because the unwrapped values are bounded by the corresponding `::Native`.
1486    let mut new_run_ends = Vec::with_capacity(1);
1487    let mut take_value_indices = Vec::with_capacity(1);
1488    let mut take_value_is_valid = NullBufferBuilder::new(1);
1489
1490    let values_cmp = make_comparator(
1491        run_array.values().as_ref(),
1492        run_array.values().as_ref(),
1493        SortOptions::default(),
1494    )?;
1495
1496    for ix in 1..physical_indices.len() {
1497        let prev_idx = physical_indices[ix - 1];
1498        let cur_idx = physical_indices[ix];
1499        if is_new_run_take(run_array.values().as_ref(), prev_idx, cur_idx, &values_cmp) {
1500            // Safe unwrap since physical indices came from a valid run array.
1501            let index = I::Native::from_usize(prev_idx.unwrap_or_default()).unwrap();
1502            take_value_indices.push(index);
1503            take_value_is_valid
1504                .append(prev_idx.is_some_and(|idx| run_array.values().is_valid(idx)));
1505            new_run_ends.push(T::Native::from_usize(ix).unwrap());
1506        }
1507    }
1508    let last = physical_indices[physical_indices.len() - 1];
1509    // Safe unwrap since physical indices came from a valid run array.
1510    let index = I::Native::from_usize(last.unwrap_or_default()).unwrap();
1511    take_value_indices.push(index);
1512    take_value_is_valid.append(last.is_some_and(|idx| run_array.values().is_valid(idx)));
1513    new_run_ends.push(T::Native::from_usize(physical_indices.len()).unwrap());
1514
1515    // SAFETY: run-ends are strictly increasing with last value == logical length.
1516    let run_ends = unsafe {
1517        RunEndBuffer::new_unchecked(ScalarBuffer::from(new_run_ends), 0, physical_indices.len())
1518    };
1519
1520    let nulls = take_value_is_valid.finish();
1521    let take_value_indices =
1522        PrimitiveArray::<I>::new(ScalarBuffer::from(take_value_indices), nulls);
1523
1524    let new_values = take(run_array.values(), &take_value_indices, None)?;
1525
1526    // SAFETY: `new_values` has one entry per run.
1527    Ok(
1528        unsafe {
1529            RunArray::<T>::new_unchecked(run_array.data_type().clone(), run_ends, new_values)
1530        },
1531    )
1532}
1533
1534/// Physical run index for each logical take slot.
1535///
1536/// `None` means the logical index is null. Only valid indices are passed to
1537/// [`RunArray::get_physical_indices`]; a null slot's backing integer is ignored
1538/// and may be out of range.
1539fn physical_indices_for_take<T: RunEndIndexType, I: ArrowPrimitiveType>(
1540    run_array: &RunArray<T>,
1541    logical_indices: &PrimitiveArray<I>,
1542) -> Result<Vec<Option<usize>>, ArrowError> {
1543    if logical_indices.null_count() == 0 {
1544        return Ok(run_array
1545            .get_physical_indices(logical_indices.values())?
1546            .into_iter()
1547            .map(Some)
1548            .collect());
1549    }
1550
1551    let valid_logical: Vec<_> = logical_indices.iter().flatten().collect();
1552
1553    let valid_physical = if valid_logical.is_empty() {
1554        Vec::new()
1555    } else {
1556        run_array.get_physical_indices(&valid_logical)?
1557    };
1558
1559    let mut valid_physical = valid_physical.into_iter();
1560    Ok(logical_indices
1561        .iter()
1562        .map(|index| index.map(|_| valid_physical.next().unwrap()))
1563        .collect())
1564}
1565
1566fn is_new_run_take(
1567    values: &dyn Array,
1568    prev_idx: Option<usize>,
1569    cur_idx: Option<usize>,
1570    values_cmp: &arrow_cmp::DynComparator,
1571) -> bool {
1572    let prev_valid = prev_idx.is_some_and(|idx| values.is_valid(idx));
1573    let cur_valid = cur_idx.is_some_and(|idx| values.is_valid(idx));
1574    match (prev_valid, cur_valid) {
1575        (false, false) => false,
1576        (true, true) => {
1577            let prev = prev_idx.unwrap();
1578            let cur = cur_idx.unwrap();
1579            prev != cur && values_cmp(cur, prev).is_ne()
1580        }
1581        _ => true,
1582    }
1583}
1584
1585/// Takes/filters a fixed size list array's inner data using the offsets of the list array.
1586fn take_value_indices_from_fixed_size_list<IndexType>(
1587    list: &FixedSizeListArray,
1588    indices: &PrimitiveArray<IndexType>,
1589    length: <UInt32Type as ArrowPrimitiveType>::Native,
1590) -> Result<PrimitiveArray<UInt32Type>, ArrowError>
1591where
1592    IndexType: ArrowPrimitiveType,
1593{
1594    let mut values = UInt32Builder::with_capacity(length as usize * indices.len());
1595
1596    for i in 0..indices.len() {
1597        if indices.is_valid(i) {
1598            let index = indices
1599                .value(i)
1600                .to_usize()
1601                .ok_or_else(|| ArrowError::ComputeError("Cast to usize failed".to_string()))?;
1602            let start = u32::try_from(list.value_offset_at(index)).map_err(|_| {
1603                ArrowError::ComputeError("FixedSizeList offset overflows u32".to_string())
1604            })?;
1605
1606            // Safety: Range always has known length.
1607            unsafe {
1608                values.append_trusted_len_iter(start..start + length);
1609            }
1610        } else {
1611            values.append_nulls(length as usize);
1612        }
1613    }
1614
1615    Ok(values.finish())
1616}
1617
1618/// To avoid generating take implementations for every index type, instead we
1619/// only generate for UInt32 and UInt64 and coerce inputs to these types
1620trait ToIndices {
1621    type T: ArrowPrimitiveType;
1622
1623    fn to_indices(&self) -> PrimitiveArray<Self::T>;
1624}
1625
1626macro_rules! to_indices_reinterpret {
1627    ($t:ty, $o:ty) => {
1628        impl ToIndices for PrimitiveArray<$t> {
1629            type T = $o;
1630
1631            fn to_indices(&self) -> PrimitiveArray<$o> {
1632                let cast = ScalarBuffer::new(self.values().inner().clone(), 0, self.len());
1633                PrimitiveArray::new(cast, self.nulls().cloned())
1634            }
1635        }
1636    };
1637}
1638
1639macro_rules! to_indices_identity {
1640    ($t:ty) => {
1641        impl ToIndices for PrimitiveArray<$t> {
1642            type T = $t;
1643
1644            fn to_indices(&self) -> PrimitiveArray<$t> {
1645                self.clone()
1646            }
1647        }
1648    };
1649}
1650
1651macro_rules! to_indices_widening {
1652    ($t:ty, $o:ty) => {
1653        impl ToIndices for PrimitiveArray<$t> {
1654            type T = UInt32Type;
1655
1656            fn to_indices(&self) -> PrimitiveArray<$o> {
1657                let cast = self.values().iter().copied().map(|x| x as _).collect();
1658                PrimitiveArray::new(cast, self.nulls().cloned())
1659            }
1660        }
1661    };
1662}
1663
1664to_indices_widening!(UInt8Type, UInt32Type);
1665to_indices_widening!(Int8Type, UInt32Type);
1666
1667to_indices_widening!(UInt16Type, UInt32Type);
1668to_indices_widening!(Int16Type, UInt32Type);
1669
1670to_indices_identity!(UInt32Type);
1671to_indices_reinterpret!(Int32Type, UInt32Type);
1672
1673to_indices_identity!(UInt64Type);
1674to_indices_reinterpret!(Int64Type, UInt64Type);
1675
1676/// Take rows by index from [`RecordBatch`] and returns a new [`RecordBatch`] from those indexes.
1677///
1678/// This function will call [`take`] on each array of the [`RecordBatch`] and assemble a new [`RecordBatch`].
1679///
1680/// # Errors
1681/// This function errors whenever:
1682/// * `indices` is not an integer array
1683/// * A non-null index is not less than the number of rows
1684/// * A taken column's offsets overflow, e.g. more than `i32::MAX` bytes of `Utf8` data
1685///
1686/// # Example
1687/// ```
1688/// # use std::sync::Arc;
1689/// # use arrow_array::{StringArray, Int32Array, UInt32Array, RecordBatch};
1690/// # use arrow_schema::{DataType, Field, Schema};
1691/// # use arrow_select::take::take_record_batch;
1692/// let schema = Arc::new(Schema::new(vec![
1693///     Field::new("a", DataType::Int32, true),
1694///     Field::new("b", DataType::Utf8, true),
1695/// ]));
1696/// let batch = RecordBatch::try_new(
1697///     schema.clone(),
1698///     vec![
1699///         Arc::new(Int32Array::from_iter_values(0..20)),
1700///         Arc::new(StringArray::from_iter_values(
1701///             (0..20).map(|i| format!("str-{}", i)),
1702///         )),
1703///     ],
1704/// )
1705/// .unwrap();
1706///
1707/// let indices = UInt32Array::from(vec![1, 5, 10]);
1708/// let taken = take_record_batch(&batch, &indices).unwrap();
1709///
1710/// let expected = RecordBatch::try_new(
1711///     schema,
1712///     vec![
1713///         Arc::new(Int32Array::from(vec![1, 5, 10])),
1714///         Arc::new(StringArray::from(vec!["str-1", "str-5", "str-10"])),
1715///     ],
1716/// )
1717/// .unwrap();
1718/// assert_eq!(taken, expected);
1719/// ```
1720pub fn take_record_batch(
1721    record_batch: &RecordBatch,
1722    indices: &dyn Array,
1723) -> Result<RecordBatch, ArrowError> {
1724    downcast_integer_array!(
1725        indices => {
1726            let indices = indices.to_indices();
1727            // Check once against the row count, which every column shares. A checked take of
1728            // one column would not do: some types (e.g. `Null`) read no index.
1729            check_bounds(record_batch.num_rows(), &indices)?;
1730            let columns = record_batch
1731                .columns()
1732                .iter()
1733                .map(|c| take_impl::<_, false>(c.as_ref(), &indices))
1734                .collect::<Result<Vec<_>, _>>()?;
1735            // Null indices can put nulls in non-nullable columns, which this rejects. The
1736            // row count is needed for a batch with no columns.
1737            let options = RecordBatchOptions::new().with_row_count(Some(indices.len()));
1738            RecordBatch::try_new_with_options(record_batch.schema(), columns, &options)
1739        },
1740        d => Err(ArrowError::InvalidArgumentError(format!("Take only supported for integers, got {d:?}")))
1741    )
1742}
1743
1744#[cfg(test)]
1745mod tests {
1746    use super::*;
1747    use arrow_array::builder::*;
1748    use arrow_buffer::{IntervalDayTime, IntervalMonthDayNano};
1749    use arrow_schema::{Field, Fields, Schema, TimeUnit, UnionFields};
1750    use num_traits::ToPrimitive;
1751
1752    fn test_take_decimal_arrays(
1753        data: Vec<Option<i128>>,
1754        index: &UInt32Array,
1755        options: Option<TakeOptions>,
1756        expected_data: Vec<Option<i128>>,
1757        precision: &u8,
1758        scale: &i8,
1759    ) -> Result<(), ArrowError> {
1760        let output = data
1761            .into_iter()
1762            .collect::<Decimal128Array>()
1763            .with_precision_and_scale(*precision, *scale)
1764            .unwrap();
1765
1766        let expected = expected_data
1767            .into_iter()
1768            .collect::<Decimal128Array>()
1769            .with_precision_and_scale(*precision, *scale)
1770            .unwrap();
1771
1772        let expected = Arc::new(expected) as ArrayRef;
1773        let output = take(&output, index, options).unwrap();
1774        assert_eq!(&output, &expected);
1775        Ok(())
1776    }
1777
1778    fn test_take_boolean_arrays(
1779        data: Vec<Option<bool>>,
1780        index: &UInt32Array,
1781        options: Option<TakeOptions>,
1782        expected_data: Vec<Option<bool>>,
1783    ) {
1784        let output = BooleanArray::from(data);
1785        let expected = Arc::new(BooleanArray::from(expected_data)) as ArrayRef;
1786        let output = take(&output, index, options).unwrap();
1787        assert_eq!(&output, &expected)
1788    }
1789
1790    fn test_take_primitive_arrays<T>(
1791        data: Vec<Option<T::Native>>,
1792        index: &UInt32Array,
1793        options: Option<TakeOptions>,
1794        expected_data: Vec<Option<T::Native>>,
1795    ) -> Result<(), ArrowError>
1796    where
1797        T: ArrowPrimitiveType,
1798        PrimitiveArray<T>: From<Vec<Option<T::Native>>>,
1799    {
1800        let output = PrimitiveArray::<T>::from(data);
1801        let expected = Arc::new(PrimitiveArray::<T>::from(expected_data)) as ArrayRef;
1802        let output = take(&output, index, options)?;
1803        assert_eq!(&output, &expected);
1804        Ok(())
1805    }
1806
1807    fn test_take_primitive_arrays_non_null<T>(
1808        data: Vec<T::Native>,
1809        index: &UInt32Array,
1810        options: Option<TakeOptions>,
1811        expected_data: Vec<Option<T::Native>>,
1812    ) -> Result<(), ArrowError>
1813    where
1814        T: ArrowPrimitiveType,
1815        PrimitiveArray<T>: From<Vec<T::Native>>,
1816        PrimitiveArray<T>: From<Vec<Option<T::Native>>>,
1817    {
1818        let output = PrimitiveArray::<T>::from(data);
1819        let expected = Arc::new(PrimitiveArray::<T>::from(expected_data)) as ArrayRef;
1820        let output = take(&output, index, options)?;
1821        assert_eq!(&output, &expected);
1822        Ok(())
1823    }
1824
1825    fn test_take_impl_primitive_arrays<T, I>(
1826        data: Vec<Option<T::Native>>,
1827        index: &PrimitiveArray<I>,
1828        options: Option<TakeOptions>,
1829        expected_data: Vec<Option<T::Native>>,
1830    ) where
1831        T: ArrowPrimitiveType,
1832        PrimitiveArray<T>: From<Vec<Option<T::Native>>>,
1833        I: ArrowPrimitiveType,
1834    {
1835        let output = PrimitiveArray::<T>::from(data);
1836        let expected = PrimitiveArray::<T>::from(expected_data);
1837        let output = take(&output, index, options).unwrap();
1838        let output = output.as_any().downcast_ref::<PrimitiveArray<T>>().unwrap();
1839        assert_eq!(output, &expected)
1840    }
1841
1842    // create a simple struct for testing purposes
1843    fn create_test_struct(values: Vec<Option<(Option<bool>, Option<i32>)>>) -> StructArray {
1844        let mut struct_builder = StructBuilder::new(
1845            Fields::from(vec![
1846                Field::new("a", DataType::Boolean, true),
1847                Field::new("b", DataType::Int32, true),
1848            ]),
1849            vec![
1850                Box::new(BooleanBuilder::with_capacity(values.len())),
1851                Box::new(Int32Builder::with_capacity(values.len())),
1852            ],
1853        );
1854
1855        for value in values {
1856            struct_builder
1857                .field_builder::<BooleanBuilder>(0)
1858                .unwrap()
1859                .append_option(value.and_then(|v| v.0));
1860            struct_builder
1861                .field_builder::<Int32Builder>(1)
1862                .unwrap()
1863                .append_option(value.and_then(|v| v.1));
1864            struct_builder.append(value.is_some());
1865        }
1866        struct_builder.finish()
1867    }
1868
1869    #[test]
1870    fn test_take_decimal128_non_null_indices() {
1871        let index = UInt32Array::from(vec![0, 5, 3, 1, 4, 2]);
1872        let precision: u8 = 10;
1873        let scale: i8 = 5;
1874        test_take_decimal_arrays(
1875            vec![None, Some(3), Some(5), Some(2), Some(3), None],
1876            &index,
1877            None,
1878            vec![None, None, Some(2), Some(3), Some(3), Some(5)],
1879            &precision,
1880            &scale,
1881        )
1882        .unwrap();
1883    }
1884
1885    #[test]
1886    fn test_take_decimal128() {
1887        let index = UInt32Array::from(vec![Some(3), None, Some(1), Some(3), Some(2)]);
1888        let precision: u8 = 10;
1889        let scale: i8 = 5;
1890        test_take_decimal_arrays(
1891            vec![Some(0), Some(1), Some(2), Some(3), Some(4)],
1892            &index,
1893            None,
1894            vec![Some(3), None, Some(1), Some(3), Some(2)],
1895            &precision,
1896            &scale,
1897        )
1898        .unwrap();
1899    }
1900
1901    #[test]
1902    fn test_take_primitive_non_null_indices() {
1903        let index = UInt32Array::from(vec![0, 5, 3, 1, 4, 2]);
1904        test_take_primitive_arrays::<Int8Type>(
1905            vec![None, Some(3), Some(5), Some(2), Some(3), None],
1906            &index,
1907            None,
1908            vec![None, None, Some(2), Some(3), Some(3), Some(5)],
1909        )
1910        .unwrap();
1911    }
1912
1913    #[test]
1914    fn test_take_primitive_non_null_values() {
1915        let index = UInt32Array::from(vec![Some(3), None, Some(1), Some(3), Some(2)]);
1916        test_take_primitive_arrays::<Int8Type>(
1917            vec![Some(0), Some(1), Some(2), Some(3), Some(4)],
1918            &index,
1919            None,
1920            vec![Some(3), None, Some(1), Some(3), Some(2)],
1921        )
1922        .unwrap();
1923    }
1924
1925    #[test]
1926    fn test_take_primitive_non_null() {
1927        let index = UInt32Array::from(vec![0, 5, 3, 1, 4, 2]);
1928        test_take_primitive_arrays::<Int8Type>(
1929            vec![Some(0), Some(3), Some(5), Some(2), Some(3), Some(1)],
1930            &index,
1931            None,
1932            vec![Some(0), Some(1), Some(2), Some(3), Some(3), Some(5)],
1933        )
1934        .unwrap();
1935    }
1936
1937    #[test]
1938    fn test_take_primitive_nullable_indices_non_null_values_with_offset() {
1939        let index = UInt32Array::from(vec![Some(0), Some(1), Some(2), Some(3), None, None]);
1940        let index = index.slice(2, 4);
1941        let index = index.as_any().downcast_ref::<UInt32Array>().unwrap();
1942
1943        assert_eq!(
1944            index,
1945            &UInt32Array::from(vec![Some(2), Some(3), None, None])
1946        );
1947
1948        test_take_primitive_arrays_non_null::<Int64Type>(
1949            vec![0, 10, 20, 30, 40, 50],
1950            index,
1951            None,
1952            vec![Some(20), Some(30), None, None],
1953        )
1954        .unwrap();
1955    }
1956
1957    #[test]
1958    fn test_take_primitive_nullable_indices_nullable_values_with_offset() {
1959        let index = UInt32Array::from(vec![Some(0), Some(1), Some(2), Some(3), None, None]);
1960        let index = index.slice(2, 4);
1961        let index = index.as_any().downcast_ref::<UInt32Array>().unwrap();
1962
1963        assert_eq!(
1964            index,
1965            &UInt32Array::from(vec![Some(2), Some(3), None, None])
1966        );
1967
1968        test_take_primitive_arrays::<Int64Type>(
1969            vec![None, None, Some(20), Some(30), Some(40), Some(50)],
1970            index,
1971            None,
1972            vec![Some(20), Some(30), None, None],
1973        )
1974        .unwrap();
1975    }
1976
1977    #[test]
1978    fn test_take_primitive() {
1979        let index = UInt32Array::from(vec![Some(3), None, Some(1), Some(3), Some(2)]);
1980
1981        // int8
1982        test_take_primitive_arrays::<Int8Type>(
1983            vec![Some(0), None, Some(2), Some(3), None],
1984            &index,
1985            None,
1986            vec![Some(3), None, None, Some(3), Some(2)],
1987        )
1988        .unwrap();
1989
1990        // int16
1991        test_take_primitive_arrays::<Int16Type>(
1992            vec![Some(0), None, Some(2), Some(3), None],
1993            &index,
1994            None,
1995            vec![Some(3), None, None, Some(3), Some(2)],
1996        )
1997        .unwrap();
1998
1999        // int32
2000        test_take_primitive_arrays::<Int32Type>(
2001            vec![Some(0), None, Some(2), Some(3), None],
2002            &index,
2003            None,
2004            vec![Some(3), None, None, Some(3), Some(2)],
2005        )
2006        .unwrap();
2007
2008        // int64
2009        test_take_primitive_arrays::<Int64Type>(
2010            vec![Some(0), None, Some(2), Some(3), None],
2011            &index,
2012            None,
2013            vec![Some(3), None, None, Some(3), Some(2)],
2014        )
2015        .unwrap();
2016
2017        // uint8
2018        test_take_primitive_arrays::<UInt8Type>(
2019            vec![Some(0), None, Some(2), Some(3), None],
2020            &index,
2021            None,
2022            vec![Some(3), None, None, Some(3), Some(2)],
2023        )
2024        .unwrap();
2025
2026        // uint16
2027        test_take_primitive_arrays::<UInt16Type>(
2028            vec![Some(0), None, Some(2), Some(3), None],
2029            &index,
2030            None,
2031            vec![Some(3), None, None, Some(3), Some(2)],
2032        )
2033        .unwrap();
2034
2035        // uint32
2036        test_take_primitive_arrays::<UInt32Type>(
2037            vec![Some(0), None, Some(2), Some(3), None],
2038            &index,
2039            None,
2040            vec![Some(3), None, None, Some(3), Some(2)],
2041        )
2042        .unwrap();
2043
2044        // int64
2045        test_take_primitive_arrays::<Int64Type>(
2046            vec![Some(0), None, Some(2), Some(-15), None],
2047            &index,
2048            None,
2049            vec![Some(-15), None, None, Some(-15), Some(2)],
2050        )
2051        .unwrap();
2052
2053        // interval_year_month
2054        test_take_primitive_arrays::<IntervalYearMonthType>(
2055            vec![Some(0), None, Some(2), Some(-15), None],
2056            &index,
2057            None,
2058            vec![Some(-15), None, None, Some(-15), Some(2)],
2059        )
2060        .unwrap();
2061
2062        // interval_day_time
2063        let v1 = IntervalDayTime::new(0, 0);
2064        let v2 = IntervalDayTime::new(2, 0);
2065        let v3 = IntervalDayTime::new(-15, 0);
2066        test_take_primitive_arrays::<IntervalDayTimeType>(
2067            vec![Some(v1), None, Some(v2), Some(v3), None],
2068            &index,
2069            None,
2070            vec![Some(v3), None, None, Some(v3), Some(v2)],
2071        )
2072        .unwrap();
2073
2074        // interval_month_day_nano
2075        let v1 = IntervalMonthDayNano::new(0, 0, 0);
2076        let v2 = IntervalMonthDayNano::new(2, 0, 0);
2077        let v3 = IntervalMonthDayNano::new(-15, 0, 0);
2078        test_take_primitive_arrays::<IntervalMonthDayNanoType>(
2079            vec![Some(v1), None, Some(v2), Some(v3), None],
2080            &index,
2081            None,
2082            vec![Some(v3), None, None, Some(v3), Some(v2)],
2083        )
2084        .unwrap();
2085
2086        // duration_second
2087        test_take_primitive_arrays::<DurationSecondType>(
2088            vec![Some(0), None, Some(2), Some(-15), None],
2089            &index,
2090            None,
2091            vec![Some(-15), None, None, Some(-15), Some(2)],
2092        )
2093        .unwrap();
2094
2095        // duration_millisecond
2096        test_take_primitive_arrays::<DurationMillisecondType>(
2097            vec![Some(0), None, Some(2), Some(-15), None],
2098            &index,
2099            None,
2100            vec![Some(-15), None, None, Some(-15), Some(2)],
2101        )
2102        .unwrap();
2103
2104        // duration_microsecond
2105        test_take_primitive_arrays::<DurationMicrosecondType>(
2106            vec![Some(0), None, Some(2), Some(-15), None],
2107            &index,
2108            None,
2109            vec![Some(-15), None, None, Some(-15), Some(2)],
2110        )
2111        .unwrap();
2112
2113        // duration_nanosecond
2114        test_take_primitive_arrays::<DurationNanosecondType>(
2115            vec![Some(0), None, Some(2), Some(-15), None],
2116            &index,
2117            None,
2118            vec![Some(-15), None, None, Some(-15), Some(2)],
2119        )
2120        .unwrap();
2121
2122        // float32
2123        test_take_primitive_arrays::<Float32Type>(
2124            vec![Some(0.0), None, Some(2.21), Some(-3.1), None],
2125            &index,
2126            None,
2127            vec![Some(-3.1), None, None, Some(-3.1), Some(2.21)],
2128        )
2129        .unwrap();
2130
2131        // float64
2132        test_take_primitive_arrays::<Float64Type>(
2133            vec![Some(0.0), None, Some(2.21), Some(-3.1), None],
2134            &index,
2135            None,
2136            vec![Some(-3.1), None, None, Some(-3.1), Some(2.21)],
2137        )
2138        .unwrap();
2139    }
2140
2141    #[test]
2142    fn test_take_preserve_timezone() {
2143        let index = Int64Array::from(vec![Some(0), None]);
2144
2145        let input = TimestampNanosecondArray::from(vec![
2146            1_639_715_368_000_000_000,
2147            1_639_715_368_000_000_000,
2148        ])
2149        .with_timezone("UTC".to_string());
2150        let result = take(&input, &index, None).unwrap();
2151        match result.data_type() {
2152            DataType::Timestamp(TimeUnit::Nanosecond, tz) => {
2153                assert_eq!(tz.clone(), Some("UTC".into()))
2154            }
2155            _ => panic!(),
2156        }
2157    }
2158
2159    #[test]
2160    fn test_take_impl_primitive_with_int64_indices() {
2161        let index = Int64Array::from(vec![Some(3), None, Some(1), Some(3), Some(2)]);
2162
2163        // int16
2164        test_take_impl_primitive_arrays::<Int16Type, Int64Type>(
2165            vec![Some(0), None, Some(2), Some(3), None],
2166            &index,
2167            None,
2168            vec![Some(3), None, None, Some(3), Some(2)],
2169        );
2170
2171        // int64
2172        test_take_impl_primitive_arrays::<Int64Type, Int64Type>(
2173            vec![Some(0), None, Some(2), Some(-15), None],
2174            &index,
2175            None,
2176            vec![Some(-15), None, None, Some(-15), Some(2)],
2177        );
2178
2179        // uint64
2180        test_take_impl_primitive_arrays::<UInt64Type, Int64Type>(
2181            vec![Some(0), None, Some(2), Some(3), None],
2182            &index,
2183            None,
2184            vec![Some(3), None, None, Some(3), Some(2)],
2185        );
2186
2187        // duration_millisecond
2188        test_take_impl_primitive_arrays::<DurationMillisecondType, Int64Type>(
2189            vec![Some(0), None, Some(2), Some(-15), None],
2190            &index,
2191            None,
2192            vec![Some(-15), None, None, Some(-15), Some(2)],
2193        );
2194
2195        // float32
2196        test_take_impl_primitive_arrays::<Float32Type, Int64Type>(
2197            vec![Some(0.0), None, Some(2.21), Some(-3.1), None],
2198            &index,
2199            None,
2200            vec![Some(-3.1), None, None, Some(-3.1), Some(2.21)],
2201        );
2202    }
2203
2204    #[test]
2205    fn test_take_impl_primitive_with_uint8_indices() {
2206        let index = UInt8Array::from(vec![Some(3), None, Some(1), Some(3), Some(2)]);
2207
2208        // int16
2209        test_take_impl_primitive_arrays::<Int16Type, UInt8Type>(
2210            vec![Some(0), None, Some(2), Some(3), None],
2211            &index,
2212            None,
2213            vec![Some(3), None, None, Some(3), Some(2)],
2214        );
2215
2216        // duration_millisecond
2217        test_take_impl_primitive_arrays::<DurationMillisecondType, UInt8Type>(
2218            vec![Some(0), None, Some(2), Some(-15), None],
2219            &index,
2220            None,
2221            vec![Some(-15), None, None, Some(-15), Some(2)],
2222        );
2223
2224        // float32
2225        test_take_impl_primitive_arrays::<Float32Type, UInt8Type>(
2226            vec![Some(0.0), None, Some(2.21), Some(-3.1), None],
2227            &index,
2228            None,
2229            vec![Some(-3.1), None, None, Some(-3.1), Some(2.21)],
2230        );
2231    }
2232
2233    #[test]
2234    fn test_take_bool() {
2235        let index = UInt32Array::from(vec![Some(3), None, Some(1), Some(3), Some(2)]);
2236        // boolean
2237        test_take_boolean_arrays(
2238            vec![Some(false), None, Some(true), Some(false), None],
2239            &index,
2240            None,
2241            vec![Some(false), None, None, Some(false), Some(true)],
2242        );
2243    }
2244
2245    #[test]
2246    fn test_take_bool_nullable_index() {
2247        // indices where the masked invalid elements would be out of bounds
2248        let index = UInt32Array::new(
2249            ScalarBuffer::from(vec![99, 0, 999, 1, 9999, 2]),
2250            Some(NullBuffer::from(vec![
2251                false, true, false, true, false, true,
2252            ])),
2253        );
2254        test_take_boolean_arrays(
2255            vec![Some(true), None, Some(false)],
2256            &index,
2257            None,
2258            vec![None, Some(true), None, None, None, Some(false)],
2259        );
2260    }
2261
2262    #[test]
2263    fn test_take_bool_nullable_index_nonnull_values() {
2264        // indices where the masked invalid elements would be out of bounds
2265        let index = UInt32Array::new(
2266            ScalarBuffer::from(vec![99, 0, 999, 1, 9999, 2]),
2267            Some(NullBuffer::from(vec![
2268                false, true, false, true, false, true,
2269            ])),
2270        );
2271        test_take_boolean_arrays(
2272            vec![Some(true), Some(true), Some(false)],
2273            &index,
2274            None,
2275            vec![None, Some(true), None, Some(true), None, Some(false)],
2276        );
2277    }
2278
2279    #[test]
2280    fn test_take_bool_with_offset() {
2281        let index = UInt32Array::from(vec![Some(3), None, Some(1), Some(3), Some(2), None]);
2282        let index = index.slice(2, 4);
2283        let index = index
2284            .as_any()
2285            .downcast_ref::<PrimitiveArray<UInt32Type>>()
2286            .unwrap();
2287
2288        // boolean
2289        test_take_boolean_arrays(
2290            vec![Some(false), None, Some(true), Some(false), None],
2291            index,
2292            None,
2293            vec![None, Some(false), Some(true), None],
2294        );
2295    }
2296
2297    #[test]
2298    // Null indices + sliced source boolean array — exercises src_offset in the sparse take_bits path.
2299    fn test_take_bool_nullable_index_sliced_source() {
2300        let source = BooleanArray::from(vec![Some(true), Some(false), Some(true), Some(false)]);
2301        let source = source.slice(1, 3); // logical: [false, true, false], offset=1
2302        let source = source;
2303
2304        let indices = UInt32Array::from(vec![Some(2), None, Some(0)]);
2305        let result = take(&source, &indices, None).unwrap();
2306        let result = result.as_any().downcast_ref::<BooleanArray>().unwrap();
2307
2308        let expected = BooleanArray::from(vec![Some(false), None, Some(false)]);
2309        assert_eq!(result, &expected);
2310    }
2311
2312    #[test]
2313    // >8 elements: exercises the 8-at-a-time unrolled byte packing in take_bits.
2314    fn test_take_bool_no_nulls_multi_byte() {
2315        let source = BooleanArray::from(vec![
2316            true, false, true, true, false, false, true, false, true, true,
2317        ]);
2318        let indices = UInt32Array::from(vec![0, 2, 4, 6, 8, 1, 3, 5, 7, 9]);
2319        let result = take(&source, &indices, None).unwrap();
2320        let result = result.as_any().downcast_ref::<BooleanArray>().unwrap();
2321        let expected = BooleanArray::from(vec![
2322            true, true, false, true, true, false, true, false, false, true,
2323        ]);
2324        assert_eq!(result, &expected);
2325    }
2326
2327    #[test]
2328    // Sliced source: verifies src_offset is applied when no null indices.
2329    fn test_take_bool_no_nulls_sliced_source() {
2330        let source = BooleanArray::from(vec![true, false, true, false, true]);
2331        let source = source.slice(2, 3); // [true, false, true], offset=2
2332        let source = source.as_any().downcast_ref::<BooleanArray>().unwrap();
2333        let indices = UInt32Array::from(vec![2, 0, 1]);
2334        let result = take(source, &indices, None).unwrap();
2335        let result = result.as_any().downcast_ref::<BooleanArray>().unwrap();
2336        let expected = BooleanArray::from(vec![true, true, false]);
2337        assert_eq!(result, &expected);
2338    }
2339
2340    #[test]
2341    // Nullable source, >8 elements: exercises the 8-at-a-time unrolled byte packing in take_bits_with_validity.
2342    fn test_take_bool_nullable_values_multi_byte() {
2343        let source = BooleanArray::from(vec![
2344            Some(true),
2345            None,
2346            Some(false),
2347            Some(true),
2348            None,
2349            Some(false),
2350            Some(true),
2351            Some(false),
2352            Some(true),
2353            None,
2354        ]);
2355        let indices = UInt32Array::from(vec![0, 2, 4, 6, 8, 1, 3, 5, 7, 9]);
2356        let result = take(&source, &indices, None).unwrap();
2357        let result = result.as_any().downcast_ref::<BooleanArray>().unwrap();
2358        let expected = BooleanArray::from(vec![
2359            Some(true),
2360            Some(false),
2361            None,
2362            Some(true),
2363            Some(true),
2364            None,
2365            Some(true),
2366            Some(false),
2367            Some(false),
2368            None,
2369        ]);
2370        assert_eq!(result, &expected);
2371    }
2372
2373    #[test]
2374    // Nullable source, null indices, sliced source: verifies src_offset with both null paths.
2375    fn test_take_bool_nullable_values_sliced_source_null_indices() {
2376        let source =
2377            BooleanArray::from(vec![Some(true), Some(false), None, Some(true), Some(false)]);
2378        let source = source.slice(1, 4); // [false, null, true, false], offset=1
2379        let source = source.as_any().downcast_ref::<BooleanArray>().unwrap();
2380        let indices = UInt32Array::from(vec![Some(3), None, Some(1), Some(0)]);
2381        let result = take(source, &indices, None).unwrap();
2382        let result = result.as_any().downcast_ref::<BooleanArray>().unwrap();
2383        let expected = BooleanArray::from(vec![Some(false), None, None, Some(false)]);
2384        assert_eq!(result, &expected);
2385    }
2386
2387    #[test]
2388    #[should_panic(expected = "assertion failed: idx < self.bit_len")]
2389    fn test_take_bool_oob_no_check_bounds_panics() {
2390        let array = BooleanArray::from(vec![true, false, true]);
2391        let indices = Int32Array::from(vec![0, 1, 10]);
2392        take(&array, &indices, None).unwrap();
2393    }
2394
2395    fn _test_take_string<'a, K>()
2396    where
2397        K: Array + PartialEq + From<Vec<Option<&'a str>>> + 'static,
2398    {
2399        let index = UInt32Array::from(vec![Some(3), None, Some(1), Some(3), Some(4)]);
2400
2401        let array = K::from(vec![
2402            Some("one"),
2403            None,
2404            Some("three"),
2405            Some("four"),
2406            Some("five"),
2407        ]);
2408        let actual = take(&array, &index, None).unwrap();
2409        assert_eq!(actual.len(), index.len());
2410
2411        let actual = actual.as_any().downcast_ref::<K>().unwrap();
2412
2413        let expected = K::from(vec![Some("four"), None, None, Some("four"), Some("five")]);
2414
2415        assert_eq!(actual, &expected);
2416    }
2417
2418    #[test]
2419    fn test_take_string() {
2420        _test_take_string::<StringArray>()
2421    }
2422
2423    #[test]
2424    fn test_take_large_string() {
2425        _test_take_string::<LargeStringArray>()
2426    }
2427
2428    #[test]
2429    fn test_take_slice_string() {
2430        let strings = StringArray::from(vec![Some("hello"), None, Some("world"), None, Some("hi")]);
2431        let indices = Int32Array::from(vec![Some(0), Some(1), None, Some(0), Some(2)]);
2432        let indices_slice = indices.slice(1, 4);
2433        let expected = StringArray::from(vec![None, None, Some("hello"), Some("world")]);
2434        let result = take(&strings, &indices_slice, None).unwrap();
2435        assert_eq!(result.as_ref(), &expected);
2436    }
2437
2438    /// Take from a *sliced* byte array, i.e. one whose value offsets do not
2439    /// start at zero. This exercises copying byte data out of an array with a
2440    /// non-zero base offset for both the no-null fast path and the nullable
2441    /// path (null indices and selected null values).
2442    #[test]
2443    fn test_take_bytes_sliced_values() {
2444        let values = StringArray::from(vec![
2445            Some("aaa"),
2446            Some("bbb"),
2447            None,
2448            Some("ccccc"),
2449            Some("dd"),
2450            None,
2451            Some("eeee"),
2452        ]);
2453        // Slice so the underlying value offsets no longer start at 0:
2454        // sliced == [None, "ccccc", "dd", None, "eeee"]
2455        let sliced = values.slice(2, 5);
2456
2457        // Fast path: every output slot is valid (no null indices, no null
2458        // values selected).
2459        let indices = Int32Array::from(vec![1, 2, 4, 1]);
2460        let result = take(&sliced, &indices, None).unwrap();
2461        let expected =
2462            StringArray::from(vec![Some("ccccc"), Some("dd"), Some("eeee"), Some("ccccc")]);
2463        assert_eq!(result.as_string::<i32>(), &expected);
2464
2465        // Nullable path: a null index (position 1) and selected null values
2466        // (sliced indices 0 and 3 are null).
2467        let indices = Int32Array::from(vec![Some(1), None, Some(0), Some(4), Some(3)]);
2468        let result = take(&sliced, &indices, None).unwrap();
2469        let expected = StringArray::from(vec![Some("ccccc"), None, None, Some("eeee"), None]);
2470        assert_eq!(result.as_string::<i32>(), &expected);
2471    }
2472
2473    fn _test_byte_view<T>()
2474    where
2475        T: ByteViewType,
2476        str: AsRef<T::Native>,
2477        T::Native: PartialEq,
2478    {
2479        let index = UInt32Array::from(vec![Some(3), None, Some(1), Some(3), Some(4), Some(2)]);
2480        let array = {
2481            // ["hello", "world", null, "large payload over 12 bytes", "lulu"]
2482            let mut builder = GenericByteViewBuilder::<T>::new();
2483            builder.append_value("hello");
2484            builder.append_value("world");
2485            builder.append_null();
2486            builder.append_value("large payload over 12 bytes");
2487            builder.append_value("lulu");
2488            builder.finish()
2489        };
2490
2491        let actual = take(&array, &index, None).unwrap();
2492
2493        assert_eq!(actual.len(), index.len());
2494        let actual_buffers = actual.as_byte_view::<T>().data_buffers();
2495        let input_buffers = array.data_buffers();
2496        assert!(Arc::ptr_eq(actual_buffers, input_buffers));
2497
2498        let expected = {
2499            // ["large payload over 12 bytes", null, "world", "large payload over 12 bytes", "lulu", null]
2500            let mut builder = GenericByteViewBuilder::<T>::new();
2501            builder.append_value("large payload over 12 bytes");
2502            builder.append_null();
2503            builder.append_value("world");
2504            builder.append_value("large payload over 12 bytes");
2505            builder.append_value("lulu");
2506            builder.append_null();
2507            builder.finish()
2508        };
2509
2510        assert_eq!(actual.as_ref(), &expected);
2511    }
2512
2513    #[test]
2514    fn test_take_string_view() {
2515        _test_byte_view::<StringViewType>()
2516    }
2517
2518    #[test]
2519    fn test_take_binary_view() {
2520        _test_byte_view::<BinaryViewType>()
2521    }
2522
2523    macro_rules! test_take_list {
2524        ($offset_type:ty, $list_data_type:ident, $list_array_type:ident) => {{
2525            // Construct a value array, [[0,0,0], [-1,-2,-1], [], [2,3]]
2526            let values = Arc::new(Int32Array::from(vec![0, 0, 0, -1, -2, -1, 2, 3]));
2527            let value_offsets =
2528                OffsetBuffer::<$offset_type>::new(ScalarBuffer::from(vec![0, 3, 6, 6, 8]));
2529            let field = Arc::new(Field::new_list_field(DataType::Int32, false));
2530            let list_array = $list_array_type::new(Arc::clone(&field), value_offsets, values, None);
2531
2532            // index returns: [[2,3], null, [-1,-2,-1], [], [0,0,0]]
2533            let index = UInt32Array::from(vec![Some(3), None, Some(1), Some(2), Some(0)]);
2534
2535            let a = take(&list_array, &index, None).unwrap();
2536            let a: &$list_array_type = a.as_any().downcast_ref::<$list_array_type>().unwrap();
2537
2538            // construct a value array with expected results:
2539            // [[2,3], null, [-1,-2,-1], [], [0,0,0]]
2540            let expected_values = Arc::new(Int32Array::from(vec![
2541                Some(2),
2542                Some(3),
2543                Some(-1),
2544                Some(-2),
2545                Some(-1),
2546                Some(0),
2547                Some(0),
2548                Some(0),
2549            ]));
2550            let expected_offsets =
2551                OffsetBuffer::<$offset_type>::new(ScalarBuffer::from(vec![0, 2, 2, 5, 5, 8]));
2552            let expected_list_array = $list_array_type::new(
2553                field,
2554                expected_offsets,
2555                expected_values,
2556                // null buffer remains the same as only the indices have nulls
2557                index.nulls().cloned(),
2558            );
2559
2560            assert_eq!(a, &expected_list_array);
2561        }};
2562    }
2563
2564    macro_rules! test_take_list_with_value_nulls {
2565        ($offset_type:ty, $list_data_type:ident, $list_array_type:ident) => {{
2566            // Construct a value array, [[0,null,0], [-1,-2,3], [null], [5,null]]
2567            let values = Arc::new(Int32Array::from(vec![
2568                Some(0),
2569                None,
2570                Some(0),
2571                Some(-1),
2572                Some(-2),
2573                Some(3),
2574                None,
2575                Some(5),
2576                None,
2577            ]));
2578            let value_offsets =
2579                OffsetBuffer::<$offset_type>::new(ScalarBuffer::from(vec![0, 3, 6, 7, 9]));
2580            let field = Arc::new(Field::new_list_field(DataType::Int32, true));
2581            let list_array = $list_array_type::new(Arc::clone(&field), value_offsets, values, None);
2582
2583            // index returns: [[null], null, [-1,-2,3], [2,null], [0,null,0]]
2584            let index = UInt32Array::from(vec![Some(2), None, Some(1), Some(3), Some(0)]);
2585
2586            let a = take(&list_array, &index, None).unwrap();
2587            let a: &$list_array_type = a.as_any().downcast_ref::<$list_array_type>().unwrap();
2588
2589            // construct a value array with expected results:
2590            // [[null], null, [-1,-2,3], [5,null], [0,null,0]]
2591            let expected_values = Arc::new(Int32Array::from(vec![
2592                None,
2593                Some(-1),
2594                Some(-2),
2595                Some(3),
2596                Some(5),
2597                None,
2598                Some(0),
2599                None,
2600                Some(0),
2601            ]));
2602            let expected_offsets =
2603                OffsetBuffer::<$offset_type>::new(ScalarBuffer::from(vec![0, 1, 1, 4, 6, 9]));
2604            let expected_list_array = $list_array_type::new(
2605                field,
2606                expected_offsets,
2607                expected_values,
2608                // null buffer remains the same as only the indices have nulls
2609                index.nulls().cloned(),
2610            );
2611
2612            assert_eq!(a, &expected_list_array);
2613        }};
2614    }
2615
2616    macro_rules! test_take_list_with_nulls {
2617        ($offset_type:ty, $list_data_type:ident, $list_array_type:ident) => {{
2618            // Construct a value array, [[0,null,0], [-1,-2,3], null, [5,null]]
2619            let values = Arc::new(Int32Array::from(vec![
2620                Some(0),
2621                None,
2622                Some(0),
2623                Some(-1),
2624                Some(-2),
2625                Some(3),
2626                Some(5),
2627                None,
2628            ]));
2629            let value_offsets =
2630                OffsetBuffer::<$offset_type>::new(ScalarBuffer::from(vec![0, 3, 6, 6, 8]));
2631            let field = Arc::new(Field::new_list_field(DataType::Int32, true));
2632            // the entry at index 2 is null
2633            let list_nulls = NullBuffer::from(vec![true, true, false, true]);
2634            let list_array =
2635                $list_array_type::new(Arc::clone(&field), value_offsets, values, Some(list_nulls));
2636
2637            // index returns: [null, null, [-1,-2,3], [5,null], [0,null,0]]
2638            let index = UInt32Array::from(vec![Some(2), None, Some(1), Some(3), Some(0)]);
2639
2640            let a = take(&list_array, &index, None).unwrap();
2641            let a: &$list_array_type = a.as_any().downcast_ref::<$list_array_type>().unwrap();
2642
2643            // construct a value array with expected results:
2644            // [null, null, [-1,-2,3], [5,null], [0,null,0]]
2645            let expected_values = Arc::new(Int32Array::from(vec![
2646                Some(-1),
2647                Some(-2),
2648                Some(3),
2649                Some(5),
2650                None,
2651                Some(0),
2652                None,
2653                Some(0),
2654            ]));
2655            let expected_offsets =
2656                OffsetBuffer::<$offset_type>::new(ScalarBuffer::from(vec![0, 0, 0, 3, 5, 8]));
2657            // null buffer must be recalculated as both values and indices have nulls
2658            let expected_nulls = NullBuffer::from(vec![false, false, true, true, true]);
2659            let expected_list_array = $list_array_type::new(
2660                field,
2661                expected_offsets,
2662                expected_values,
2663                Some(expected_nulls),
2664            );
2665
2666            assert_eq!(a, &expected_list_array);
2667        }};
2668    }
2669
2670    fn test_take_list_view_generic<OffsetType: OffsetSizeTrait, ValuesType: ArrowPrimitiveType, F>(
2671        values: Vec<Option<Vec<Option<ValuesType::Native>>>>,
2672        take_indices: Vec<Option<usize>>,
2673        expected: Vec<Option<Vec<Option<ValuesType::Native>>>>,
2674        mapper: F,
2675    ) where
2676        F: Fn(GenericListViewArray<OffsetType>) -> GenericListViewArray<OffsetType>,
2677    {
2678        let mut list_view_array =
2679            GenericListViewBuilder::<OffsetType, _>::new(PrimitiveBuilder::<ValuesType>::new());
2680
2681        for value in values {
2682            list_view_array.append_option(value);
2683        }
2684        let list_view_array = list_view_array.finish();
2685        let list_view_array = mapper(list_view_array);
2686
2687        let mut indices = UInt64Builder::new();
2688        for idx in take_indices {
2689            indices.append_option(idx.map(|i| i.to_u64().unwrap()));
2690        }
2691        let indices = indices.finish();
2692
2693        let taken = take(&list_view_array, &indices, None)
2694            .unwrap()
2695            .as_list_view()
2696            .clone();
2697
2698        let mut expected_array =
2699            GenericListViewBuilder::<OffsetType, _>::new(PrimitiveBuilder::<ValuesType>::new());
2700        for value in expected {
2701            expected_array.append_option(value);
2702        }
2703        let expected_array = expected_array.finish();
2704
2705        assert_eq!(taken, expected_array);
2706    }
2707
2708    macro_rules! list_view_test_case {
2709        (values: $values:expr, indices: $indices:expr, expected: $expected: expr) => {{
2710            test_take_list_view_generic::<i32, Int8Type, _>($values, $indices, $expected, |x| x);
2711            test_take_list_view_generic::<i64, Int8Type, _>($values, $indices, $expected, |x| x);
2712        }};
2713        (values: $values:expr, transform: $fn:expr, indices: $indices:expr, expected: $expected: expr) => {{
2714            test_take_list_view_generic::<i32, Int8Type, _>($values, $indices, $expected, $fn);
2715            test_take_list_view_generic::<i64, Int8Type, _>($values, $indices, $expected, $fn);
2716        }};
2717    }
2718
2719    fn do_take_fixed_size_list_test<T>(
2720        length: <Int32Type as ArrowPrimitiveType>::Native,
2721        input_data: Vec<Option<Vec<Option<T::Native>>>>,
2722        indices: Vec<<UInt32Type as ArrowPrimitiveType>::Native>,
2723        expected_data: Vec<Option<Vec<Option<T::Native>>>>,
2724    ) where
2725        T: ArrowPrimitiveType,
2726        PrimitiveArray<T>: From<Vec<Option<T::Native>>>,
2727    {
2728        let indices = UInt32Array::from(indices);
2729
2730        let input_array = FixedSizeListArray::from_iter_primitive::<T, _, _>(input_data, length);
2731
2732        let output =
2733            take_fixed_size_list::<_, true>(&input_array, &indices, length as u32).unwrap();
2734
2735        let expected = FixedSizeListArray::from_iter_primitive::<T, _, _>(expected_data, length);
2736
2737        assert_eq!(&output, &expected)
2738    }
2739
2740    #[test]
2741    // Fast path (primitive child, no child nulls) with null indices — verifies offset backfill for null slots.
2742    fn test_take_list_primitive_child_null_indices() {
2743        // Row sizes deliberately vary (1, 3, 2) so the test exercises
2744        // non-uniform offset arithmetic, not just uniform stride.
2745        let list = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
2746            Some(vec![Some(1)]),
2747            Some(vec![Some(2), Some(3), Some(4)]),
2748            Some(vec![Some(5), Some(6)]),
2749        ]);
2750        let indices = Int32Array::from(vec![Some(2), None, Some(0), Some(1)]);
2751        let result = take(&list, &indices, None).unwrap();
2752        let result = result.as_any().downcast_ref::<ListArray>().unwrap();
2753
2754        let expected = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
2755            Some(vec![Some(5), Some(6)]),
2756            None,
2757            Some(vec![Some(1)]),
2758            Some(vec![Some(2), Some(3), Some(4)]),
2759        ]);
2760        assert_eq!(result, &expected);
2761    }
2762
2763    #[test]
2764    fn test_take_list() {
2765        test_take_list!(i32, List, ListArray);
2766    }
2767
2768    #[test]
2769    fn test_take_large_list() {
2770        test_take_list!(i64, LargeList, LargeListArray);
2771    }
2772
2773    #[test]
2774    fn test_take_list_with_value_nulls() {
2775        test_take_list_with_value_nulls!(i32, List, ListArray);
2776    }
2777
2778    #[test]
2779    fn test_take_large_list_with_value_nulls() {
2780        test_take_list_with_value_nulls!(i64, LargeList, LargeListArray);
2781    }
2782
2783    #[test]
2784    fn test_test_take_list_with_nulls() {
2785        test_take_list_with_nulls!(i32, List, ListArray);
2786    }
2787
2788    #[test]
2789    fn test_test_take_large_list_with_nulls() {
2790        test_take_list_with_nulls!(i64, LargeList, LargeListArray);
2791    }
2792
2793    #[test]
2794    fn test_test_take_list_view_reversed() {
2795        // Take reversed indices
2796        list_view_test_case! {
2797            values: vec![
2798                Some(vec![Some(1), None, Some(3)]),
2799                None,
2800                Some(vec![Some(7), Some(8), None]),
2801            ],
2802            indices: vec![Some(2), Some(1), Some(0)],
2803            expected: vec![
2804                Some(vec![Some(7), Some(8), None]),
2805                None,
2806                Some(vec![Some(1), None, Some(3)]),
2807            ]
2808        }
2809    }
2810
2811    #[test]
2812    fn test_take_list_view_null_indices() {
2813        // Take with null indices
2814        list_view_test_case! {
2815            values: vec![
2816                Some(vec![Some(1), None, Some(3)]),
2817                None,
2818                Some(vec![Some(7), Some(8), None]),
2819            ],
2820            indices: vec![None, Some(0), None],
2821            expected: vec![None, Some(vec![Some(1), None, Some(3)]), None]
2822        }
2823    }
2824
2825    #[test]
2826    fn test_take_list_view_null_values() {
2827        // Take at null values
2828        list_view_test_case! {
2829            values: vec![
2830                Some(vec![Some(1), None, Some(3)]),
2831                None,
2832                Some(vec![Some(7), Some(8), None]),
2833            ],
2834            indices: vec![Some(1), Some(1), Some(1), None, None],
2835            expected: vec![None; 5]
2836        }
2837    }
2838
2839    #[test]
2840    fn test_take_list_view_sliced() {
2841        // Take null indices/values, with slicing.
2842        list_view_test_case! {
2843            values: vec![
2844                Some(vec![Some(1)]),
2845                None,
2846                None,
2847                Some(vec![Some(2), Some(3)]),
2848                Some(vec![Some(4), Some(5)]),
2849                None,
2850            ],
2851            transform: |l| l.slice(2, 4),
2852            indices: vec![Some(0), Some(3), None, Some(1), Some(2)],
2853            expected: vec![
2854                None, None, None, Some(vec![Some(2), Some(3)]), Some(vec![Some(4), Some(5)])
2855            ]
2856        }
2857    }
2858
2859    #[test]
2860    fn test_take_fixed_size_list() {
2861        do_take_fixed_size_list_test::<Int32Type>(
2862            3,
2863            vec![
2864                Some(vec![None, Some(1), Some(2)]),
2865                Some(vec![Some(3), Some(4), None]),
2866                Some(vec![Some(6), Some(7), Some(8)]),
2867            ],
2868            vec![2, 1, 0],
2869            vec![
2870                Some(vec![Some(6), Some(7), Some(8)]),
2871                Some(vec![Some(3), Some(4), None]),
2872                Some(vec![None, Some(1), Some(2)]),
2873            ],
2874        );
2875
2876        do_take_fixed_size_list_test::<UInt8Type>(
2877            1,
2878            vec![
2879                Some(vec![Some(1)]),
2880                Some(vec![Some(2)]),
2881                Some(vec![Some(3)]),
2882                Some(vec![Some(4)]),
2883                Some(vec![Some(5)]),
2884                Some(vec![Some(6)]),
2885                Some(vec![Some(7)]),
2886                Some(vec![Some(8)]),
2887            ],
2888            vec![2, 7, 0],
2889            vec![
2890                Some(vec![Some(3)]),
2891                Some(vec![Some(8)]),
2892                Some(vec![Some(1)]),
2893            ],
2894        );
2895
2896        do_take_fixed_size_list_test::<UInt64Type>(
2897            3,
2898            vec![
2899                Some(vec![Some(10), Some(11), Some(12)]),
2900                Some(vec![Some(13), Some(14), Some(15)]),
2901                None,
2902                Some(vec![Some(16), Some(17), Some(18)]),
2903            ],
2904            vec![3, 2, 1, 2, 0],
2905            vec![
2906                Some(vec![Some(16), Some(17), Some(18)]),
2907                None,
2908                Some(vec![Some(13), Some(14), Some(15)]),
2909                None,
2910                Some(vec![Some(10), Some(11), Some(12)]),
2911            ],
2912        );
2913    }
2914
2915    #[test]
2916    fn test_take_fixed_size_binary_with_nulls_indices() {
2917        let fsb = FixedSizeBinaryArray::try_from_sparse_iter_with_size(
2918            [
2919                Some(vec![0x01, 0x01, 0x01, 0x01]),
2920                Some(vec![0x02, 0x02, 0x02, 0x02]),
2921                Some(vec![0x03, 0x03, 0x03, 0x03]),
2922                Some(vec![0x04, 0x04, 0x04, 0x04]),
2923            ]
2924            .into_iter(),
2925            4,
2926        )
2927        .unwrap();
2928
2929        // The two middle indices are null -> Should be null in the output.
2930        let indices = UInt32Array::from(vec![Some(0), None, None, Some(3)]);
2931
2932        let result = take_fixed_size_binary::<_, true>(&fsb, &indices, 4).unwrap();
2933        assert_eq!(result.len(), 4);
2934        assert_eq!(result.null_count(), 2);
2935        assert_eq!(
2936            result.nulls().unwrap().iter().collect::<Vec<_>>(),
2937            vec![true, false, false, true]
2938        );
2939    }
2940
2941    /// The [`take_fixed_size_binary`] kernel contains optimizations that provide a faster
2942    /// implementation for commonly-used value lengths. This test uses a value length that is not
2943    /// optimized to test both code paths.
2944    #[test]
2945    fn test_take_fixed_size_binary_with_nulls_indices_not_optimized_length() {
2946        let fsb = FixedSizeBinaryArray::try_from_sparse_iter_with_size(
2947            [
2948                Some(vec![0x01, 0x01, 0x01, 0x01, 0x01]),
2949                Some(vec![0x02, 0x02, 0x02, 0x02, 0x01]),
2950                Some(vec![0x03, 0x03, 0x03, 0x03, 0x01]),
2951                Some(vec![0x04, 0x04, 0x04, 0x04, 0x01]),
2952            ]
2953            .into_iter(),
2954            5,
2955        )
2956        .unwrap();
2957
2958        // The two middle indices are null -> Should be null in the output.
2959        let indices = UInt32Array::from(vec![Some(0), None, None, Some(3)]);
2960
2961        let result = take_fixed_size_binary::<_, true>(&fsb, &indices, 5).unwrap();
2962        assert_eq!(result.len(), 4);
2963        assert_eq!(result.null_count(), 2);
2964        assert_eq!(
2965            result.nulls().unwrap().iter().collect::<Vec<_>>(),
2966            vec![true, false, false, true]
2967        );
2968    }
2969
2970    #[test]
2971    #[should_panic(expected = "index out of bounds: the len is 4 but the index is 1000")]
2972    fn test_take_list_out_of_bounds() {
2973        // Construct a value array, [[0,0,0], [-1,-2,-1], [2,3]]
2974        let values = Arc::new(Int32Array::from(vec![0, 0, 0, -1, -2, -1, 2, 3]));
2975        // Construct offsets
2976        let value_offsets = OffsetBuffer::<i32>::new(ScalarBuffer::from(vec![0, 3, 6, 8]));
2977        // Construct a list array from the above two
2978        let field = Arc::new(Field::new_list_field(DataType::Int32, false));
2979        let list_array = ListArray::new(field, value_offsets, values, None);
2980
2981        let index = UInt32Array::from(vec![1000]);
2982
2983        // A panic is expected here since we have not supplied the check_bounds
2984        // option.
2985        take(&list_array, &index, None).unwrap();
2986    }
2987
2988    #[test]
2989    fn test_take_map() {
2990        let values = Int32Array::from(vec![1, 2, 3, 4]);
2991        let array =
2992            MapArray::new_from_strings(vec!["a", "b", "c", "a"].into_iter(), &values, &[0, 3, 4])
2993                .unwrap();
2994
2995        let index = UInt32Array::from(vec![0]);
2996
2997        let result = take(&array, &index, None).unwrap();
2998        let expected: ArrayRef = Arc::new(
2999            MapArray::new_from_strings(
3000                vec!["a", "b", "c"].into_iter(),
3001                &values.slice(0, 3),
3002                &[0, 3],
3003            )
3004            .unwrap(),
3005        );
3006        assert_eq!(&expected, &result);
3007    }
3008
3009    #[test]
3010    fn test_take_struct() {
3011        let array = create_test_struct(vec![
3012            Some((Some(true), Some(42))),
3013            Some((Some(false), Some(28))),
3014            Some((Some(false), Some(19))),
3015            Some((Some(true), Some(31))),
3016            None,
3017        ]);
3018
3019        let index = UInt32Array::from(vec![0, 3, 1, 0, 2, 4]);
3020        let actual = take(&array, &index, None).unwrap();
3021        let actual: &StructArray = actual.as_any().downcast_ref::<StructArray>().unwrap();
3022        assert_eq!(index.len(), actual.len());
3023        assert_eq!(1, actual.null_count());
3024
3025        let expected = create_test_struct(vec![
3026            Some((Some(true), Some(42))),
3027            Some((Some(true), Some(31))),
3028            Some((Some(false), Some(28))),
3029            Some((Some(true), Some(42))),
3030            Some((Some(false), Some(19))),
3031            None,
3032        ]);
3033
3034        assert_eq!(&expected, actual);
3035
3036        let nulls = NullBuffer::from(&[false, true, false, true, false, true]);
3037        let empty_struct_arr = StructArray::new_empty_fields(6, Some(nulls));
3038        let index = UInt32Array::from(vec![0, 2, 1, 4]);
3039        let actual = take(&empty_struct_arr, &index, None).unwrap();
3040
3041        let expected_nulls = NullBuffer::from(&[false, false, true, false]);
3042        let expected_struct_arr = StructArray::new_empty_fields(4, Some(expected_nulls));
3043        assert_eq!(&expected_struct_arr, actual.as_struct());
3044    }
3045
3046    #[test]
3047    fn test_take_struct_with_null_indices() {
3048        let array = create_test_struct(vec![
3049            Some((Some(true), Some(42))),
3050            Some((Some(false), Some(28))),
3051            Some((Some(false), Some(19))),
3052            Some((Some(true), Some(31))),
3053            None,
3054        ]);
3055
3056        let index = UInt32Array::from(vec![None, Some(3), Some(1), None, Some(0), Some(4)]);
3057        let actual = take(&array, &index, None).unwrap();
3058        let actual: &StructArray = actual.as_any().downcast_ref::<StructArray>().unwrap();
3059        assert_eq!(index.len(), actual.len());
3060        assert_eq!(3, actual.null_count()); // 2 because of indices, 1 because of struct array
3061
3062        let expected = create_test_struct(vec![
3063            None,
3064            Some((Some(true), Some(31))),
3065            Some((Some(false), Some(28))),
3066            None,
3067            Some((Some(true), Some(42))),
3068            None,
3069        ]);
3070
3071        assert_eq!(&expected, actual);
3072    }
3073
3074    #[test]
3075    fn test_take_out_of_bounds() {
3076        let index = UInt32Array::from(vec![Some(3), None, Some(1), Some(3), Some(6)]);
3077        let take_opt = TakeOptions { check_bounds: true };
3078
3079        // int64
3080        let result = test_take_primitive_arrays::<Int64Type>(
3081            vec![Some(0), None, Some(2), Some(3), None],
3082            &index,
3083            Some(take_opt),
3084            vec![None],
3085        );
3086        assert!(result.is_err());
3087    }
3088
3089    #[test]
3090    #[should_panic(expected = "index out of bounds: the len is 4 but the index is 1000")]
3091    fn test_take_out_of_bounds_panic() {
3092        let index = UInt32Array::from(vec![Some(1000)]);
3093
3094        test_take_primitive_arrays::<Int64Type>(
3095            vec![Some(0), Some(1), Some(2), Some(3)],
3096            &index,
3097            None,
3098            vec![None],
3099        )
3100        .unwrap();
3101    }
3102
3103    #[test]
3104    fn test_null_array_smaller_than_indices() {
3105        let values = NullArray::new(2);
3106        let indices = UInt32Array::from(vec![Some(0), None, Some(15)]);
3107
3108        let result = take(&values, &indices, None).unwrap();
3109        let expected: ArrayRef = Arc::new(NullArray::new(3));
3110        assert_eq!(&result, &expected);
3111    }
3112
3113    #[test]
3114    fn test_null_array_larger_than_indices() {
3115        let values = NullArray::new(5);
3116        let indices = UInt32Array::from(vec![Some(0), None, Some(15)]);
3117
3118        let result = take(&values, &indices, None).unwrap();
3119        let expected: ArrayRef = Arc::new(NullArray::new(3));
3120        assert_eq!(&result, &expected);
3121    }
3122
3123    #[test]
3124    fn test_null_array_indices_out_of_bounds() {
3125        let values = NullArray::new(5);
3126        let indices = UInt32Array::from(vec![Some(0), None, Some(15)]);
3127
3128        let result = take(&values, &indices, Some(TakeOptions { check_bounds: true }));
3129        assert_eq!(
3130            result.unwrap_err().to_string(),
3131            "Compute error: Array index out of bounds, cannot get item at index 15 from 5 entries"
3132        );
3133    }
3134
3135    #[test]
3136    fn test_take_dict() {
3137        let mut dict_builder = StringDictionaryBuilder::<Int16Type>::new();
3138
3139        dict_builder.append("foo").unwrap();
3140        dict_builder.append("bar").unwrap();
3141        dict_builder.append("").unwrap();
3142        dict_builder.append_null();
3143        dict_builder.append("foo").unwrap();
3144        dict_builder.append("bar").unwrap();
3145        dict_builder.append("bar").unwrap();
3146        dict_builder.append("foo").unwrap();
3147
3148        let array = dict_builder.finish();
3149        let dict_values = array.values().clone();
3150        let dict_values = dict_values.as_any().downcast_ref::<StringArray>().unwrap();
3151
3152        let indices = UInt32Array::from(vec![
3153            Some(0), // first "foo"
3154            Some(7), // last "foo"
3155            None,    // null index should return null
3156            Some(5), // second "bar"
3157            Some(6), // another "bar"
3158            Some(2), // empty string
3159            Some(3), // input is null at this index
3160        ]);
3161
3162        let result = take(&array, &indices, None).unwrap();
3163        let result = result
3164            .as_any()
3165            .downcast_ref::<DictionaryArray<Int16Type>>()
3166            .unwrap();
3167
3168        let result_values: StringArray = result.values().to_data().into();
3169
3170        // dictionary values should stay the same
3171        let expected_values = StringArray::from(vec!["foo", "bar", ""]);
3172        assert_eq!(&expected_values, dict_values);
3173        assert_eq!(&expected_values, &result_values);
3174
3175        let expected_keys = Int16Array::from(vec![
3176            Some(0),
3177            Some(0),
3178            None,
3179            Some(1),
3180            Some(1),
3181            Some(2),
3182            None,
3183        ]);
3184        assert_eq!(result.keys(), &expected_keys);
3185    }
3186
3187    fn build_generic_list<S, T>(data: Vec<Option<Vec<T::Native>>>) -> GenericListArray<S>
3188    where
3189        S: OffsetSizeTrait + 'static,
3190        T: ArrowPrimitiveType,
3191        PrimitiveArray<T>: From<Vec<Option<T::Native>>>,
3192    {
3193        GenericListArray::from_iter_primitive::<T, _, _>(
3194            data.iter()
3195                .map(|x| x.as_ref().map(|x| x.iter().map(|x| Some(*x)))),
3196        )
3197    }
3198
3199    fn test_take_sliced_list_generic<S: OffsetSizeTrait + 'static>() {
3200        let list = build_generic_list::<S, Int32Type>(vec![
3201            Some(vec![0, 1]),
3202            Some(vec![2, 3, 4]),
3203            None,
3204            Some(vec![]),
3205            Some(vec![5, 6]),
3206            Some(vec![7]),
3207        ]);
3208        let sliced = list.slice(1, 4);
3209        let indices = UInt32Array::from(vec![Some(3), Some(0), None, Some(2), Some(1)]);
3210
3211        let taken = take(&sliced, &indices, None).unwrap();
3212        let taken = taken.as_list::<S>();
3213
3214        let expected = build_generic_list::<S, Int32Type>(vec![
3215            Some(vec![5, 6]),
3216            Some(vec![2, 3, 4]),
3217            None,
3218            Some(vec![]),
3219            None,
3220        ]);
3221
3222        assert_eq!(taken, &expected);
3223    }
3224
3225    fn test_take_sliced_list_with_value_nulls_generic<S: OffsetSizeTrait + 'static>() {
3226        let list = GenericListArray::<S>::from_iter_primitive::<Int32Type, _, _>(vec![
3227            Some(vec![Some(10)]),
3228            Some(vec![None, Some(1)]),
3229            None,
3230            Some(vec![Some(2), None]),
3231            Some(vec![]),
3232            Some(vec![Some(3)]),
3233        ]);
3234        let sliced = list.slice(1, 4);
3235        let indices = UInt32Array::from(vec![Some(2), Some(0), None, Some(3), Some(1)]);
3236
3237        let taken = take(&sliced, &indices, None).unwrap();
3238        let taken = taken.as_list::<S>();
3239
3240        let expected = GenericListArray::<S>::from_iter_primitive::<Int32Type, _, _>(vec![
3241            Some(vec![Some(2), None]),
3242            Some(vec![None, Some(1)]),
3243            None,
3244            Some(vec![]),
3245            None,
3246        ]);
3247
3248        assert_eq!(taken, &expected);
3249    }
3250
3251    #[test]
3252    fn test_take_sliced_list() {
3253        test_take_sliced_list_generic::<i32>();
3254    }
3255
3256    #[test]
3257    fn test_take_sliced_large_list() {
3258        test_take_sliced_list_generic::<i64>();
3259    }
3260
3261    #[test]
3262    fn test_take_sliced_list_with_value_nulls() {
3263        test_take_sliced_list_with_value_nulls_generic::<i32>();
3264    }
3265
3266    #[test]
3267    fn test_take_sliced_large_list_with_value_nulls() {
3268        test_take_sliced_list_with_value_nulls_generic::<i64>();
3269    }
3270
3271    #[test]
3272    fn test_take_sliced_list_memory_size() {
3273        // Takes the same rows from a two-row slice of a large array and from an unsliced
3274        // copy of those two rows. The results should be equal and use the same memory.
3275        fn check(parent: ArrayRef, unsliced: ArrayRef) {
3276            let sliced = parent.slice(500, 2);
3277            let indices = UInt32Array::from_iter_values((0..100).map(|i| i % 2));
3278            let actual = take(&sliced, &indices, None).unwrap();
3279            let expected = take(&unsliced, &indices, None).unwrap();
3280            assert_eq!(&actual, &expected);
3281            assert_eq!(
3282                actual.get_array_memory_size(),
3283                expected.get_array_memory_size()
3284            );
3285        }
3286
3287        // Lists of 10 values per row
3288        let list = |rows: usize, values: ArrayRef| -> ArrayRef {
3289            let field = Arc::new(Field::new_list_field(values.data_type().clone(), false));
3290            let offsets = OffsetBuffer::from_repeated_length(10, rows);
3291            Arc::new(ListArray::new(field, offsets, values, None))
3292        };
3293        check(
3294            list(1000, Arc::new(Int64Array::from(vec![1; 10_000]))),
3295            list(2, Arc::new(Int64Array::from(vec![1; 20]))),
3296        );
3297        check(
3298            list(1000, Arc::new(StringArray::from(vec!["a"; 10_000]))),
3299            list(2, Arc::new(StringArray::from(vec!["a"; 20]))),
3300        );
3301    }
3302
3303    #[test]
3304    fn test_take_runs() {
3305        let logical_array: Vec<i32> = vec![1_i32, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2];
3306
3307        let mut builder = PrimitiveRunBuilder::<Int32Type, Int32Type>::new();
3308        builder.extend(logical_array.into_iter().map(Some));
3309        let run_array = builder.finish();
3310
3311        let take_indices: PrimitiveArray<Int32Type> =
3312            vec![7, 2, 3, 7, 11, 4, 6].into_iter().collect();
3313
3314        let take_out = take_run(&run_array, &take_indices).unwrap();
3315
3316        assert_eq!(take_out.len(), 7);
3317        // adjacent identical values are merged: [2,2,2,2,2,1,1] -> 2 runs
3318        assert_eq!(
3319            take_out.run_ends().values().len(),
3320            2,
3321            "expected two physical runs"
3322        );
3323        assert_eq!(take_out.run_ends().values(), &[5_i32, 7]);
3324
3325        let take_out_values = take_out.values().as_primitive::<Int32Type>();
3326        assert_eq!(take_out_values.values(), &[2, 1]);
3327    }
3328
3329    #[test]
3330    fn test_take_runs_null_indices() {
3331        // A null index must not become logical index 0, and null indices must merge with
3332        // consecutive runs whose values are already null.
3333        let mut builder = PrimitiveRunBuilder::<Int32Type, Int32Type>::new();
3334        builder.extend([Some(10), Some(10), None, None, Some(99)]);
3335        let run_array = builder.finish();
3336
3337        let indices = Int32Array::from(vec![Some(0), None, Some(2), Some(3), Some(4)]);
3338        let taken = take(&run_array, &indices, None).unwrap();
3339        let run = taken.as_run::<Int32Type>();
3340        let logical: Vec<Option<i32>> = run.downcast::<Int32Array>().unwrap().into_iter().collect();
3341        assert_eq!(logical, vec![Some(10), None, None, None, Some(99)]);
3342        assert_eq!(run.run_ends().values(), &[1_i32, 4, 5]);
3343    }
3344
3345    #[test]
3346    fn test_take_runs_null_indices_non_nullable_values() {
3347        let run_array = unsafe {
3348            RunArray::<Int32Type>::new_unchecked(
3349                DataType::RunEndEncoded(
3350                    Arc::new(Field::new("run_ends", DataType::Int32, false)),
3351                    Arc::new(Field::new("values", DataType::Int32, false)),
3352                ),
3353                RunEndBuffer::new(vec![1_i32, 2].into(), 0, 2),
3354                Arc::new(Int32Array::from(vec![10, 20])),
3355            )
3356        };
3357        let indices = Int32Array::from(vec![Some(0), None]);
3358
3359        let error = take(&run_array, &indices, None).unwrap_err();
3360        assert_eq!(
3361            error.to_string(),
3362            "Compute error: Cannot take null indices from a RunEndEncoded array with a non-nullable values field"
3363        );
3364    }
3365
3366    #[test]
3367    fn test_take_runs_sliced() {
3368        let logical_array: Vec<i32> = vec![1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6];
3369
3370        let mut builder = PrimitiveRunBuilder::<Int32Type, Int32Type>::new();
3371        builder.extend(logical_array.into_iter().map(Some));
3372        let run_array = builder.finish();
3373
3374        let run_array = run_array.slice(4, 6); // [3, 3, 3, 4, 4, 5]
3375
3376        let take_indices: PrimitiveArray<Int32Type> = vec![0, 5, 5, 1, 4].into_iter().collect();
3377
3378        let result = take_run(&run_array, &take_indices).unwrap();
3379        let result = result.downcast::<Int32Array>().unwrap();
3380
3381        // [3, 5, 5, 3, 4] -> 4 physical runs (no adjacent duplicates to merge)
3382        assert_eq!(
3383            result.run_ends().values().len(),
3384            4,
3385            "expected four physical runs"
3386        );
3387        assert_eq!(result.run_ends().values(), &[1_i32, 3, 4, 5]);
3388
3389        let expected = vec![3, 5, 5, 3, 4];
3390        let actual = result.into_iter().flatten().collect::<Vec<_>>();
3391
3392        assert_eq!(expected, actual);
3393    }
3394
3395    #[test]
3396    fn test_take_value_index_from_fixed_list() {
3397        let list = FixedSizeListArray::from_iter_primitive::<Int32Type, _, _>(
3398            vec![
3399                Some(vec![Some(1), Some(2), None]),
3400                Some(vec![Some(4), None, Some(6)]),
3401                None,
3402                Some(vec![None, Some(8), Some(9)]),
3403            ],
3404            3,
3405        );
3406
3407        let indices = UInt32Array::from(vec![2, 1, 0]);
3408        let indexed = take_value_indices_from_fixed_size_list(&list, &indices, 3).unwrap();
3409
3410        assert_eq!(indexed, UInt32Array::from(vec![6, 7, 8, 3, 4, 5, 0, 1, 2]));
3411
3412        let indices = UInt32Array::from(vec![3, 2, 1, 2, 0]);
3413        let indexed = take_value_indices_from_fixed_size_list(&list, &indices, 3).unwrap();
3414
3415        assert_eq!(
3416            indexed,
3417            UInt32Array::from(vec![9, 10, 11, 6, 7, 8, 3, 4, 5, 6, 7, 8, 0, 1, 2])
3418        );
3419    }
3420
3421    #[test]
3422    fn test_take_null_indices() {
3423        // Build indices with values that are out of bounds, but masked by null mask
3424        let indices = Int32Array::new(
3425            vec![1, 2, 400, 400].into(),
3426            Some(NullBuffer::from(vec![true, true, false, false])),
3427        );
3428        let values = Int32Array::from(vec![1, 23, 4, 5]);
3429        let r = take(&values, &indices, None).unwrap();
3430        let values = r
3431            .as_primitive::<Int32Type>()
3432            .into_iter()
3433            .collect::<Vec<_>>();
3434        assert_eq!(&values, &[Some(23), Some(4), None, None])
3435    }
3436
3437    #[test]
3438    fn test_take_fixed_size_list_null_indices() {
3439        let indices = Int32Array::from_iter([Some(0), None]);
3440        let values = Arc::new(Int32Array::from(vec![0, 1, 2, 3]));
3441        let arr_field = Arc::new(Field::new_list_field(values.data_type().clone(), true));
3442        let values = FixedSizeListArray::try_new(arr_field, 2, values, None).unwrap();
3443
3444        let r = take(&values, &indices, None).unwrap();
3445        let values = r
3446            .as_fixed_size_list()
3447            .values()
3448            .as_primitive::<Int32Type>()
3449            .into_iter()
3450            .collect::<Vec<_>>();
3451        assert_eq!(values, &[Some(0), Some(1), None, None])
3452    }
3453
3454    #[test]
3455    fn test_take_bytes_null_indices() {
3456        let indices = Int32Array::new(
3457            vec![0, 1, 400, 400].into(),
3458            Some(NullBuffer::from_iter(vec![true, true, false, false])),
3459        );
3460        let values = StringArray::from(vec![Some("foo"), None]);
3461        let r = take(&values, &indices, None).unwrap();
3462        let values = r.as_string::<i32>().iter().collect::<Vec<_>>();
3463        assert_eq!(&values, &[Some("foo"), None, None, None])
3464    }
3465
3466    #[test]
3467    fn test_take_union_sparse() {
3468        let structs = create_test_struct(vec![
3469            Some((Some(true), Some(42))),
3470            Some((Some(false), Some(28))),
3471            Some((Some(false), Some(19))),
3472            Some((Some(true), Some(31))),
3473            None,
3474        ]);
3475        let strings = StringArray::from(vec![Some("a"), None, Some("c"), None, Some("d")]);
3476        let type_ids = [1; 5].into_iter().collect::<ScalarBuffer<i8>>();
3477
3478        let union_fields = [
3479            (
3480                0,
3481                Arc::new(Field::new("f1", structs.data_type().clone(), true)),
3482            ),
3483            (
3484                1,
3485                Arc::new(Field::new("f2", strings.data_type().clone(), true)),
3486            ),
3487        ]
3488        .into_iter()
3489        .collect();
3490        let children = vec![Arc::new(structs) as Arc<dyn Array>, Arc::new(strings)];
3491        let array = UnionArray::try_new(union_fields, type_ids, None, children).unwrap();
3492
3493        let indices = vec![0, 3, 1, 0, 2, 4];
3494        let index = UInt32Array::from(indices.clone());
3495        let actual = take(&array, &index, None).unwrap();
3496        let actual = actual.as_any().downcast_ref::<UnionArray>().unwrap();
3497        let strings = actual.child(1);
3498        let strings = strings.as_any().downcast_ref::<StringArray>().unwrap();
3499
3500        let actual = strings.iter().collect::<Vec<_>>();
3501        let expected = vec![Some("a"), None, None, Some("a"), Some("c"), Some("d")];
3502        assert_eq!(expected, actual);
3503    }
3504
3505    #[test]
3506    fn test_take_union_dense() {
3507        let type_ids = vec![0, 1, 1, 0, 0, 1, 0];
3508        let offsets = vec![0, 0, 1, 1, 2, 2, 3];
3509        let ints = vec![10, 20, 30, 40];
3510        let strings = vec![Some("a"), None, Some("c"), Some("d")];
3511
3512        let indices = vec![0, 3, 1, 0, 2, 4];
3513
3514        let taken_type_ids = vec![0, 0, 1, 0, 1, 0];
3515        let taken_offsets = vec![0, 1, 0, 2, 1, 3];
3516        let taken_ints = vec![10, 20, 10, 30];
3517        let taken_strings = vec![Some("a"), None];
3518
3519        let type_ids = <ScalarBuffer<i8>>::from(type_ids);
3520        let offsets = <ScalarBuffer<i32>>::from(offsets);
3521        let ints = UInt32Array::from(ints);
3522        let strings = StringArray::from(strings);
3523
3524        let union_fields = [
3525            (
3526                0,
3527                Arc::new(Field::new("f1", ints.data_type().clone(), true)),
3528            ),
3529            (
3530                1,
3531                Arc::new(Field::new("f2", strings.data_type().clone(), true)),
3532            ),
3533        ]
3534        .into_iter()
3535        .collect();
3536
3537        let array = UnionArray::try_new(
3538            union_fields,
3539            type_ids,
3540            Some(offsets),
3541            vec![Arc::new(ints), Arc::new(strings)],
3542        )
3543        .unwrap();
3544
3545        let index = UInt32Array::from(indices);
3546
3547        let actual = take(&array, &index, None).unwrap();
3548        let actual = actual.as_any().downcast_ref::<UnionArray>().unwrap();
3549
3550        assert_eq!(actual.offsets(), Some(&ScalarBuffer::from(taken_offsets)));
3551        assert_eq!(actual.type_ids(), &ScalarBuffer::from(taken_type_ids));
3552        assert_eq!(
3553            UInt32Array::from(actual.child(0).to_data()),
3554            UInt32Array::from(taken_ints)
3555        );
3556        assert_eq!(
3557            StringArray::from(actual.child(1).to_data()),
3558            StringArray::from(taken_strings)
3559        );
3560    }
3561
3562    fn union_i32_logical(array: &UnionArray) -> Vec<Option<i32>> {
3563        (0..array.len())
3564            .map(|i| {
3565                let child = array.child(array.type_id(i)).as_primitive::<Int32Type>();
3566                let offset = array.value_offset(i);
3567                if child.is_null(offset) {
3568                    None
3569                } else {
3570                    Some(child.value(offset))
3571                }
3572            })
3573            .collect()
3574    }
3575
3576    #[test]
3577    fn test_take_union_dense_null_indices() {
3578        // Dense [1, 2, 3]; a null index must not become child offset 0. Use a non-zero
3579        // type id to verify null indices don't use the invalid default type id 0.
3580        let fields =
3581            UnionFields::try_new(vec![5], vec![Field::new("i", DataType::Int32, true)]).unwrap();
3582        let dense = UnionArray::try_new(
3583            fields.clone(),
3584            ScalarBuffer::from(vec![5_i8, 5, 5]),
3585            Some(ScalarBuffer::from(vec![0_i32, 1, 2])),
3586            vec![Arc::new(Int32Array::from(vec![1, 2, 3]))],
3587        )
3588        .unwrap();
3589        let sparse = UnionArray::try_new(
3590            fields,
3591            ScalarBuffer::from(vec![5_i8, 5, 5]),
3592            None,
3593            vec![Arc::new(Int32Array::from(vec![1, 2, 3]))],
3594        )
3595        .unwrap();
3596
3597        // Use an out-of-bounds backing value for the null index to exercise `take_native`'s
3598        // default type id path. A union need not have a child with type id 0.
3599        let indices = UInt32Array::new(
3600            ScalarBuffer::from(vec![0_u32, 99, 2]),
3601            Some(NullBuffer::from(vec![true, false, true])),
3602        );
3603        let dense_taken = take(&dense, &indices, None).unwrap();
3604        let sparse_taken = take(&sparse, &indices, None).unwrap();
3605        let dense_logical = union_i32_logical(dense_taken.as_any().downcast_ref().unwrap());
3606        let sparse_logical = union_i32_logical(sparse_taken.as_any().downcast_ref().unwrap());
3607
3608        assert_eq!(dense_logical, vec![Some(1), None, Some(3)]);
3609        assert_eq!(dense_logical, sparse_logical);
3610    }
3611
3612    #[test]
3613    fn test_take_dense_union_null_indices_uses_nullable_field() {
3614        let fields = UnionFields::try_new(
3615            vec![0, 1],
3616            vec![
3617                Field::new("non_nullable", DataType::Int32, false),
3618                Field::new("nullable", DataType::Int32, true),
3619            ],
3620        )
3621        .unwrap();
3622        let union = UnionArray::try_new(
3623            fields,
3624            ScalarBuffer::from(vec![0_i8]),
3625            Some(ScalarBuffer::from(vec![0_i32])),
3626            vec![
3627                Arc::new(Int32Array::from(vec![10])),
3628                Arc::new(Int32Array::from(vec![20])),
3629            ],
3630        )
3631        .unwrap();
3632
3633        let taken = take(&union, &UInt32Array::from(vec![None]), None).unwrap();
3634        let taken = taken.as_union();
3635        assert_eq!(taken.type_id(0), 1);
3636        assert!(taken.child(1).is_null(0));
3637    }
3638
3639    #[test]
3640    fn test_take_sparse_union_null_indices_uses_nullable_field() {
3641        let fields = UnionFields::try_new(
3642            vec![0, 1],
3643            vec![
3644                Field::new("non_nullable", DataType::Int32, false),
3645                Field::new("nullable", DataType::Int32, true),
3646            ],
3647        )
3648        .unwrap();
3649        let union = UnionArray::try_new(
3650            fields,
3651            ScalarBuffer::from(vec![0_i8]),
3652            None,
3653            vec![
3654                Arc::new(Int32Array::from(vec![10])),
3655                Arc::new(Int32Array::from(vec![20])),
3656            ],
3657        )
3658        .unwrap();
3659
3660        let taken = take(&union, &UInt32Array::from(vec![Some(0), None]), None).unwrap();
3661        let taken = taken.as_union();
3662        assert_eq!(taken.type_ids(), &ScalarBuffer::from(vec![0_i8, 1]));
3663        assert_eq!(taken.logical_null_count(), 1);
3664        assert_eq!(
3665            taken
3666                .child(0)
3667                .as_primitive::<Int32Type>()
3668                .iter()
3669                .collect::<Vec<_>>(),
3670            vec![Some(10), Some(10)]
3671        );
3672        assert_eq!(
3673            taken
3674                .child(1)
3675                .as_primitive::<Int32Type>()
3676                .iter()
3677                .collect::<Vec<_>>(),
3678            vec![Some(20), None]
3679        );
3680    }
3681
3682    #[test]
3683    fn test_take_sparse_union_null_indices_no_nullable_fields() {
3684        let fields = UnionFields::try_new(
3685            vec![0, 1],
3686            vec![
3687                Field::new("a", DataType::Int32, false),
3688                Field::new("b", DataType::Int32, false),
3689            ],
3690        )
3691        .unwrap();
3692        let union = UnionArray::try_new(
3693            fields,
3694            ScalarBuffer::from(vec![0_i8]),
3695            None,
3696            vec![
3697                Arc::new(Int32Array::from(vec![10])),
3698                Arc::new(Int32Array::from(vec![20])),
3699            ],
3700        )
3701        .unwrap();
3702
3703        let error = take(&union, &UInt32Array::from(vec![None]), None).unwrap_err();
3704        assert_eq!(
3705            error.to_string(),
3706            "Compute error: Cannot take null indices from a union with no field that can represent nulls"
3707        );
3708    }
3709
3710    #[test]
3711    fn test_take_empty_sparse_union_null_indices_mixed_nullability() {
3712        let fields = UnionFields::try_new(
3713            vec![0, 1],
3714            vec![
3715                Field::new("non_nullable", DataType::Int32, false),
3716                Field::new("nullable", DataType::Int32, true),
3717            ],
3718        )
3719        .unwrap();
3720        let union = UnionArray::try_new(
3721            fields,
3722            ScalarBuffer::<i8>::from(vec![]),
3723            None,
3724            vec![
3725                Arc::new(Int32Array::from(Vec::<i32>::new())),
3726                Arc::new(Int32Array::from(Vec::<i32>::new())),
3727            ],
3728        )
3729        .unwrap();
3730
3731        let taken = take(&union, &UInt32Array::from(vec![None]), None).unwrap();
3732        let taken = taken.as_union();
3733        assert_eq!(taken.len(), 1);
3734        assert_eq!(taken.type_id(0), 1);
3735        assert_eq!(taken.logical_null_count(), 1);
3736        assert!(!taken.child(0).is_null(0));
3737        assert!(taken.child(1).is_null(0));
3738    }
3739
3740    #[test]
3741    fn test_take_empty_union_without_null_indices() {
3742        let fields = UnionFields::try_new(vec![], Vec::<Field>::new()).unwrap();
3743        let indices = UInt32Array::from(Vec::<u32>::new());
3744
3745        let sparse = UnionArray::try_new(
3746            fields.clone(),
3747            ScalarBuffer::<i8>::from(vec![]),
3748            None,
3749            vec![],
3750        )
3751        .unwrap();
3752        let dense = UnionArray::try_new(
3753            fields,
3754            ScalarBuffer::<i8>::from(vec![]),
3755            Some(ScalarBuffer::<i32>::from(vec![])),
3756            vec![],
3757        )
3758        .unwrap();
3759
3760        for values in [&sparse, &dense] {
3761            let taken = take(values, &indices, None).unwrap();
3762            assert_eq!(taken.len(), 0);
3763            assert_eq!(taken.data_type(), values.data_type());
3764        }
3765    }
3766
3767    #[test]
3768    fn test_take_empty_union_with_null_indices() {
3769        let fields = UnionFields::try_new(vec![], Vec::<Field>::new()).unwrap();
3770        let indices = UInt32Array::from(vec![None]);
3771
3772        let sparse = UnionArray::try_new(
3773            fields.clone(),
3774            ScalarBuffer::<i8>::from(vec![]),
3775            None,
3776            vec![],
3777        )
3778        .unwrap();
3779        let dense = UnionArray::try_new(
3780            fields,
3781            ScalarBuffer::<i8>::from(vec![]),
3782            Some(ScalarBuffer::<i32>::from(vec![])),
3783            vec![],
3784        )
3785        .unwrap();
3786
3787        for values in [&sparse, &dense] {
3788            let error = take(values, &indices, None).unwrap_err();
3789            assert_eq!(
3790                error.to_string(),
3791                "Compute error: Cannot take null indices from a union with no field that can represent nulls"
3792            );
3793        }
3794    }
3795
3796    fn inner_union_no_nullable_children(mode: UnionMode) -> (UnionFields, UnionArray) {
3797        let fields = UnionFields::try_new(
3798            vec![0, 1],
3799            vec![
3800                Field::new("a", DataType::Int32, false),
3801                Field::new("b", DataType::Int32, false),
3802            ],
3803        )
3804        .unwrap();
3805        let children: Vec<ArrayRef> = vec![
3806            Arc::new(Int32Array::from(vec![10])),
3807            Arc::new(Int32Array::from(vec![20])),
3808        ];
3809        let array = match mode {
3810            UnionMode::Sparse => UnionArray::try_new(
3811                fields.clone(),
3812                ScalarBuffer::from(vec![0_i8]),
3813                None,
3814                children,
3815            )
3816            .unwrap(),
3817            UnionMode::Dense => UnionArray::try_new(
3818                fields.clone(),
3819                ScalarBuffer::from(vec![0_i8]),
3820                Some(ScalarBuffer::from(vec![0_i32])),
3821                children,
3822            )
3823            .unwrap(),
3824        };
3825        (fields, array)
3826    }
3827
3828    #[test]
3829    fn test_take_union_null_indices_skips_nested_union_without_nullable_children() {
3830        // The inner union field is marked nullable, but it has no nullable
3831        // children, so it cannot represent a take-null. The sibling Int32 field
3832        // can, and must be selected instead of erroring.
3833        for mode in [UnionMode::Sparse, UnionMode::Dense] {
3834            let (inner_fields, inner) = inner_union_no_nullable_children(mode);
3835            let outer_fields = UnionFields::try_new(
3836                vec![0, 1],
3837                vec![
3838                    Field::new("inner", DataType::Union(inner_fields, mode), true),
3839                    Field::new("i", DataType::Int32, true),
3840                ],
3841            )
3842            .unwrap();
3843            let children: Vec<ArrayRef> =
3844                vec![Arc::new(inner), Arc::new(Int32Array::from(vec![30]))];
3845            let outer = match mode {
3846                UnionMode::Sparse => UnionArray::try_new(
3847                    outer_fields,
3848                    ScalarBuffer::from(vec![1_i8]),
3849                    None,
3850                    children,
3851                )
3852                .unwrap(),
3853                UnionMode::Dense => UnionArray::try_new(
3854                    outer_fields,
3855                    ScalarBuffer::from(vec![1_i8]),
3856                    Some(ScalarBuffer::from(vec![0_i32])),
3857                    children,
3858                )
3859                .unwrap(),
3860            };
3861
3862            let taken = take(&outer, &UInt32Array::from(vec![None]), None).unwrap();
3863            let taken = taken.as_union();
3864            assert_eq!(taken.type_id(0), 1, "{mode:?}");
3865            assert!(taken.child(1).is_null(0), "{mode:?}");
3866            assert_eq!(taken.logical_null_count(), 1, "{mode:?}");
3867        }
3868    }
3869
3870    #[test]
3871    fn test_take_union_null_indices_nested_union_cannot_represent_null() {
3872        // A nullable-marked nested union is not a valid null child when none of
3873        // its own children can store a null.
3874        for mode in [UnionMode::Sparse, UnionMode::Dense] {
3875            let (inner_fields, inner) = inner_union_no_nullable_children(mode);
3876            let outer_fields = UnionFields::try_new(
3877                vec![0],
3878                vec![Field::new(
3879                    "inner",
3880                    DataType::Union(inner_fields, mode),
3881                    true,
3882                )],
3883            )
3884            .unwrap();
3885            let children: Vec<ArrayRef> = vec![Arc::new(inner)];
3886            let outer = match mode {
3887                UnionMode::Sparse => UnionArray::try_new(
3888                    outer_fields,
3889                    ScalarBuffer::from(vec![0_i8]),
3890                    None,
3891                    children,
3892                )
3893                .unwrap(),
3894                UnionMode::Dense => UnionArray::try_new(
3895                    outer_fields,
3896                    ScalarBuffer::from(vec![0_i8]),
3897                    Some(ScalarBuffer::from(vec![0_i32])),
3898                    children,
3899                )
3900                .unwrap(),
3901            };
3902
3903            let error = take(&outer, &UInt32Array::from(vec![None]), None).unwrap_err();
3904            assert_eq!(
3905                error.to_string(),
3906                "Compute error: Cannot take null indices from a union with no field that can represent nulls"
3907            );
3908        }
3909    }
3910
3911    #[test]
3912    fn test_take_union_null_indices_skips_ree_with_non_nullable_values() {
3913        // A nullable-marked REE child cannot represent a take-null when its
3914        // values field is non-nullable. The sibling Int32 field must be used.
3915        let run_array = unsafe {
3916            RunArray::<Int32Type>::new_unchecked(
3917                DataType::RunEndEncoded(
3918                    Arc::new(Field::new("run_ends", DataType::Int32, false)),
3919                    Arc::new(Field::new("values", DataType::Int32, false)),
3920                ),
3921                RunEndBuffer::new(vec![1_i32].into(), 0, 1),
3922                Arc::new(Int32Array::from(vec![10])),
3923            )
3924        };
3925        let fields = UnionFields::try_new(
3926            vec![0, 1],
3927            vec![
3928                Field::new("ree", run_array.data_type().clone(), true),
3929                Field::new("i", DataType::Int32, true),
3930            ],
3931        )
3932        .unwrap();
3933        let union = UnionArray::try_new(
3934            fields,
3935            ScalarBuffer::from(vec![1_i8]),
3936            None,
3937            vec![
3938                Arc::new(run_array) as ArrayRef,
3939                Arc::new(Int32Array::from(vec![30])),
3940            ],
3941        )
3942        .unwrap();
3943
3944        let taken = take(&union, &UInt32Array::from(vec![None]), None).unwrap();
3945        let taken = taken.as_union();
3946        assert_eq!(taken.type_id(0), 1);
3947        assert!(taken.child(1).is_null(0));
3948        assert_eq!(taken.logical_null_count(), 1);
3949    }
3950
3951    #[test]
3952    fn test_take_union_dense_using_builder() {
3953        let mut builder = UnionBuilder::new_dense();
3954
3955        builder.append::<Int32Type>("a", 1).unwrap();
3956        builder.append::<Float64Type>("b", 3.0).unwrap();
3957        builder.append::<Int32Type>("a", 4).unwrap();
3958        builder.append::<Int32Type>("a", 5).unwrap();
3959        builder.append::<Float64Type>("b", 2.0).unwrap();
3960
3961        let union = builder.build().unwrap();
3962
3963        let indices = UInt32Array::from(vec![2, 0, 1, 2]);
3964
3965        let mut builder = UnionBuilder::new_dense();
3966
3967        builder.append::<Int32Type>("a", 4).unwrap();
3968        builder.append::<Int32Type>("a", 1).unwrap();
3969        builder.append::<Float64Type>("b", 3.0).unwrap();
3970        builder.append::<Int32Type>("a", 4).unwrap();
3971
3972        let taken = builder.build().unwrap();
3973
3974        assert_eq!(
3975            taken.to_data(),
3976            take(&union, &indices, None).unwrap().to_data()
3977        );
3978    }
3979
3980    #[test]
3981    fn test_take_union_dense_all_match_issue_6206() {
3982        let fields = UnionFields::from_fields(vec![Field::new("a", DataType::Int64, false)]);
3983        let ints = Arc::new(Int64Array::from(vec![1, 2, 3, 4, 5]));
3984
3985        let array = UnionArray::try_new(
3986            fields,
3987            ScalarBuffer::from(vec![0_i8, 0, 0, 0, 0]),
3988            Some(ScalarBuffer::from_iter(0_i32..5)),
3989            vec![ints],
3990        )
3991        .unwrap();
3992
3993        let indices = Int64Array::from(vec![0, 2, 4]);
3994        let array = take(&array, &indices, None).unwrap();
3995        assert_eq!(array.len(), 3);
3996    }
3997
3998    /// Fixture for the offset-overflow tests: a single large value plus the
3999    /// number of times it must be selected so the cumulative offset exceeds
4000    /// `i32::MAX`. Using a large value keeps the index count (and the test
4001    /// runtime) small.
4002    fn offset_overflow_fixture() -> (StringArray, usize) {
4003        let value_len = 1_000_000;
4004        let values = StringArray::from(vec![Some("a".repeat(value_len))]);
4005        let n = i32::MAX as usize / value_len + 1;
4006        (values, n)
4007    }
4008
4009    #[test]
4010    fn test_take_bytes_offset_overflow() {
4011        let (values, n) = offset_overflow_fixture();
4012        let indices = Int32Array::from(vec![0; n]);
4013        assert!(matches!(
4014            take(&values, &indices, None),
4015            Err(ArrowError::OffsetOverflowError(_))
4016        ));
4017    }
4018
4019    /// The offset-overflow error must also be produced on the nullable code
4020    /// path (when the output contains nulls), not only on the no-null fast path.
4021    #[test]
4022    fn test_take_bytes_offset_overflow_nullable() {
4023        let (values, n) = offset_overflow_fixture();
4024        // A null index forces the output to contain nulls, exercising the
4025        // nullable code path.
4026        let validity =
4027            NullBuffer::from_iter(std::iter::once(false).chain(std::iter::repeat_n(true, n)));
4028        let indices = Int32Array::new(vec![0i32; n + 1].into(), Some(validity));
4029
4030        assert!(matches!(
4031            take(&values, &indices, None),
4032            Err(ArrowError::OffsetOverflowError(_))
4033        ));
4034    }
4035
4036    #[test]
4037    fn test_take_run_empty_indices() {
4038        let mut builder = PrimitiveRunBuilder::<Int32Type, Int32Type>::new();
4039        builder.extend([Some(1), Some(1), Some(2), Some(2)]);
4040        let run_array = builder.finish();
4041
4042        let logical_indices: PrimitiveArray<Int32Type> = PrimitiveArray::from(Vec::<i32>::new());
4043
4044        let result = take_impl::<_, true>(&run_array, &logical_indices)
4045            .expect("take_run with empty indices");
4046
4047        // Verify the result is a valid empty RunArray
4048        assert_eq!(result.len(), 0);
4049        assert_eq!(result.null_count(), 0);
4050
4051        // Verify that the result can be downcast and used without validation errors
4052        // This specifically tests that "The values in run_ends array should be strictly positive" is not triggered
4053        let run_result = result
4054            .as_any()
4055            .downcast_ref::<RunArray<Int32Type>>()
4056            .expect("result should be a RunArray");
4057        assert_eq!(run_result.run_ends().len(), 0);
4058        assert_eq!(run_result.values().len(), 0);
4059    }
4060
4061    #[test]
4062    fn test_take_run_end_encoded_merges_identical_runs() {
4063        // https://github.com/apache/arrow-rs/issues/7710
4064        // Indices [0,1,4,5] select from [1,1,0,0,1,1] — the 0s are skipped,
4065        // so the output should be a single run of 1s, not two.
4066        let mut builder = PrimitiveRunBuilder::<Int32Type, Int32Type>::new();
4067        builder.extend([1, 1, 0, 0, 1, 1].into_iter().map(Some));
4068        let ree = builder.finish();
4069
4070        let indexes = Int32Array::from_iter_values(vec![0, 1, 4, 5]);
4071        let result = take(&ree, &indexes, None).unwrap();
4072        let result = result
4073            .as_run::<Int32Type>()
4074            .downcast::<Int32Array>()
4075            .unwrap();
4076
4077        // Verify physical layout: all four logical values collapse into one run.
4078        assert_eq!(
4079            result.run_ends().values().len(),
4080            1,
4081            "expected a single physical run"
4082        );
4083        assert_eq!(result.run_ends().values(), &[4_i32]);
4084
4085        let actual = result.into_iter().flatten().collect::<Vec<_>>();
4086        assert_eq!(actual, vec![1, 1, 1, 1]);
4087    }
4088
4089    #[test]
4090    fn test_take_run_end_encoded_merges_identical_string_runs() {
4091        let mut builder = StringRunBuilder::<Int32Type>::new();
4092        builder.extend(
4093            ["bob", "bob", "alice", "alice", "bob", "bob"]
4094                .into_iter()
4095                .map(Some),
4096        );
4097        let ree = builder.finish();
4098
4099        let indexes = Int32Array::from_iter_values(vec![0, 1, 4, 5]);
4100        let result = take(&ree, &indexes, None).unwrap();
4101        let result = result
4102            .as_run::<Int32Type>()
4103            .downcast::<StringArray>()
4104            .unwrap();
4105
4106        // Verify physical layout: all four logical values collapse into one run.
4107        assert_eq!(
4108            result.run_ends().values().len(),
4109            1,
4110            "expected a single physical run"
4111        );
4112        assert_eq!(result.run_ends().values(), &[4_i32]);
4113
4114        let actual = result.into_iter().flatten().collect::<Vec<_>>();
4115        assert_eq!(actual, vec!["bob", "bob", "bob", "bob"]);
4116    }
4117
4118    #[test]
4119    fn test_take_run_end_encoded_mixed_runs() {
4120        // Validates that runs are merged whether the same logical value comes
4121        // from the same physical index (repeated indices) or distinct physical indices.
4122        let mut builder = StringRunBuilder::<Int32Type>::new();
4123        builder.extend(
4124            ["bob", "bob", "alice", "alice", "bob", "bob", "eve", "eve"]
4125                .into_iter()
4126                .map(Some),
4127        );
4128        let ree = builder.finish();
4129
4130        // [bob,bob,bob,bob,bob,alice,alice,alice,eve,eve,eve]
4131        let indexes = Int32Array::from_iter_values(vec![0, 0, 1, 4, 5, 2, 3, 2, 6, 7, 6]);
4132        let result = take(&ree, &indexes, None).unwrap();
4133        let result = result
4134            .as_run::<Int32Type>()
4135            .downcast::<StringArray>()
4136            .unwrap();
4137
4138        // Verify physical layout: 11 logical values across exactly 3 physical runs.
4139
4140        println!("run_ends_raw: {:?}", result.run_ends());
4141        println!("run_ends: {:?}", result.run_ends().values());
4142        println!("values : {:?}", result.values());
4143        assert_eq!(
4144            result.run_ends().values().len(),
4145            3,
4146            "expected three physical runs"
4147        );
4148        assert_eq!(result.run_ends().values(), &[5_i32, 8, 11]);
4149
4150        let actual = result.into_iter().flatten().collect::<Vec<_>>();
4151        assert_eq!(
4152            actual,
4153            vec![
4154                "bob", "bob", "bob", "bob", "bob", "alice", "alice", "alice", "eve", "eve", "eve"
4155            ]
4156        );
4157    }
4158
4159    // parent null rows on FixedSizeList must propagate to child elements.
4160    #[test]
4161    fn test_take_fixed_size_list_parent_nulls() {
4162        let list = FixedSizeListArray::from_iter_primitive::<Int32Type, _, _>(
4163            vec![
4164                Some(vec![Some(1), Some(2)]),
4165                None,
4166                Some(vec![Some(5), Some(6)]),
4167            ],
4168            2,
4169        );
4170
4171        let indices = UInt32Array::from(vec![2, 1, 0]);
4172        let result = take(&list, &indices, None).unwrap();
4173        let result = result.as_fixed_size_list();
4174
4175        assert_eq!(result.len(), 3);
4176        assert!(result.is_valid(0));
4177        assert!(result.is_null(1));
4178        assert!(result.is_valid(2));
4179
4180        let child = result.values().as_primitive::<Int32Type>();
4181        assert_eq!(child.value(0), 5);
4182        assert_eq!(child.value(1), 6);
4183        assert!(child.is_null(2));
4184        assert!(child.is_null(3));
4185        assert_eq!(child.value(4), 1);
4186        assert_eq!(child.value(5), 2);
4187    }
4188
4189    #[test]
4190    fn test_take_zero_sized_fixed_size_list() {
4191        let input = FixedSizeListArray::try_new_with_length(
4192            Field::new_list_field(DataType::Int32, true).into(),
4193            0,
4194            Arc::new(Int32Array::new_null(0)),
4195            None,
4196            3,
4197        )
4198        .unwrap();
4199
4200        let indices = UInt32Array::from(vec![2, 0]);
4201        let result = take(&input, &indices, None).unwrap();
4202
4203        assert_eq!(result.len(), 2);
4204    }
4205
4206    #[test]
4207    fn test_take_zero_sized_fixed_size_binary() {
4208        let input =
4209            FixedSizeBinaryArray::try_new_with_len(0, Buffer::from(Vec::<u8>::new()), None, 3)
4210                .unwrap();
4211
4212        let indices = UInt32Array::from(vec![2, 0]);
4213        let result = take(&input, &indices, None).unwrap();
4214
4215        assert_eq!(result.len(), 2);
4216    }
4217
4218    /// Non-nullable columns of 3 rows, one per layout that represents a null differently
4219    fn non_nullable_columns() -> Vec<ArrayRef> {
4220        vec![
4221            Arc::new(Int32Array::from(vec![1, 2, 3])),
4222            Arc::new(StringArray::from(vec!["a", "bb", "ccc"])),
4223            Arc::new(DictionaryArray::<Int8Type>::from_iter(["x", "y", "x"])),
4224            Arc::new(StructArray::from(vec![(
4225                Arc::new(Field::new("c", DataType::Int32, false)),
4226                Arc::new(Int32Array::from(vec![1, 2, 3])) as ArrayRef,
4227            )])),
4228            Arc::new(FixedSizeListArray::from_iter_primitive::<Int32Type, _, _>(
4229                vec![
4230                    Some(vec![Some(1)]),
4231                    Some(vec![Some(2)]),
4232                    Some(vec![Some(3)]),
4233                ],
4234                1,
4235            )),
4236        ]
4237    }
4238
4239    /// A batch with a nullable column followed by `column` in the non-nullable field "a"
4240    fn batch_with_non_nullable(column: ArrayRef) -> RecordBatch {
4241        let schema = Schema::new(vec![
4242            Field::new("n", DataType::Int32, true),
4243            Field::new("a", column.data_type().clone(), false),
4244        ]);
4245        let n = Arc::new(Int32Array::from(vec![Some(1), None, Some(3)]));
4246        RecordBatch::try_new(Arc::new(schema), vec![n, column]).unwrap()
4247    }
4248
4249    #[test]
4250    fn test_take_record_batch_null_index_non_nullable_column() {
4251        let indices = UInt32Array::from(vec![Some(2), None]);
4252        for column in non_nullable_columns() {
4253            let batch = batch_with_non_nullable(column);
4254            let err = take_record_batch(&batch, &indices).unwrap_err();
4255            assert_eq!(
4256                err.to_string(),
4257                "Invalid argument error: Column 'a' is declared as non-nullable but contains null values",
4258                "{}",
4259                batch.column(1).data_type()
4260            );
4261        }
4262    }
4263
4264    #[test]
4265    fn test_take_record_batch_non_nullable_column() {
4266        let indices = [
4267            UInt32Array::from(vec![2, 0, 2]),
4268            // A validity buffer with no nulls
4269            UInt32Array::new(vec![2, 0].into(), Some(NullBuffer::new_valid(2))),
4270        ];
4271        for column in non_nullable_columns() {
4272            let batch = batch_with_non_nullable(column);
4273            for indices in &indices {
4274                let taken = take_record_batch(&batch, indices).unwrap();
4275
4276                assert_eq!(taken.schema(), batch.schema());
4277                for (taken, column) in taken.columns().iter().zip(batch.columns()) {
4278                    assert_eq!(taken, &take(column, indices, None).unwrap());
4279                }
4280            }
4281        }
4282    }
4283
4284    #[test]
4285    fn test_take_record_batch_no_columns_row_count() {
4286        let options = RecordBatchOptions::new().with_row_count(Some(3));
4287        let batch =
4288            RecordBatch::try_new_with_options(Arc::new(Schema::empty()), vec![], &options).unwrap();
4289
4290        let indices = UInt32Array::from(vec![Some(2), None, Some(0), Some(2)]);
4291        let taken = take_record_batch(&batch, &indices).unwrap();
4292        assert_eq!(taken.num_rows(), 4);
4293    }
4294
4295    /// Columns whose `take` reads no index, so taking them alone does not check bounds
4296    fn zero_width_columns(len: usize) -> Vec<ArrayRef> {
4297        vec![
4298            Arc::new(NullArray::new(len)),
4299            Arc::new(StructArray::new_empty_fields(len, None)),
4300            Arc::new(
4301                FixedSizeListArray::try_new_with_length(
4302                    Field::new_list_field(DataType::Int32, true).into(),
4303                    0,
4304                    Arc::new(Int32Array::new_null(0)),
4305                    None,
4306                    len,
4307                )
4308                .unwrap(),
4309            ),
4310            Arc::new(
4311                FixedSizeBinaryArray::try_new_with_len(
4312                    0,
4313                    Buffer::from(Vec::<u8>::new()),
4314                    None,
4315                    len,
4316                )
4317                .unwrap(),
4318            ),
4319        ]
4320    }
4321
4322    /// A batch of 3 rows with `first` followed by columns whose `take` reads every index
4323    fn batch_with_first_column(first: ArrayRef) -> RecordBatch {
4324        RecordBatch::try_from_iter_with_nullable([
4325            ("first", first, true),
4326            (
4327                "i",
4328                Arc::new(Int32Array::from(vec![Some(1), None, Some(3)])) as ArrayRef,
4329                true,
4330            ),
4331            (
4332                "s",
4333                Arc::new(StringArray::from(vec!["a", "bb", "ccc"])),
4334                true,
4335            ),
4336            (
4337                "l",
4338                Arc::new(ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
4339                    Some(vec![Some(1)]),
4340                    None,
4341                    Some(vec![Some(3), None]),
4342                ])),
4343                true,
4344            ),
4345        ])
4346        .unwrap()
4347    }
4348
4349    #[test]
4350    fn test_take_record_batch() {
4351        let first: ArrayRef = Arc::new(BooleanArray::from(vec![true, false, true]));
4352        let mut columns = vec![first];
4353        columns.extend(zero_width_columns(3));
4354        for first in columns {
4355            let batch = batch_with_first_column(first);
4356            let indices = UInt32Array::from(vec![Some(2), None, Some(0), Some(2)]);
4357            let taken = take_record_batch(&batch, &indices).unwrap();
4358
4359            assert_eq!(taken.schema(), batch.schema());
4360            assert_eq!(taken.num_rows(), 4);
4361            for (taken, column) in taken.columns().iter().zip(batch.columns()) {
4362                assert_eq!(taken, &take(column, &indices, None).unwrap());
4363            }
4364        }
4365    }
4366
4367    #[test]
4368    fn test_take_record_batch_out_of_bounds() {
4369        let indices: [ArrayRef; 5] = [
4370            // One past the end
4371            Arc::new(UInt32Array::from(vec![0, 3])),
4372            Arc::new(UInt32Array::from(vec![None, Some(3)])),
4373            Arc::new(Int32Array::from(vec![-1])),
4374            Arc::new(Int8Array::from(vec![i8::MAX])),
4375            Arc::new(UInt64Array::from(vec![u64::MAX])),
4376        ];
4377        let first: ArrayRef = Arc::new(Int64Array::from(vec![1, 2, 3]));
4378        let mut columns = vec![first];
4379        columns.extend(zero_width_columns(3));
4380        for first in columns {
4381            let batch = batch_with_first_column(first);
4382            for indices in &indices {
4383                let err = take_record_batch(&batch, indices).unwrap_err();
4384                assert!(
4385                    err.to_string().contains("Array index out of bounds"),
4386                    "{}: {err}",
4387                    batch.column(0).data_type()
4388                );
4389            }
4390        }
4391    }
4392
4393    #[test]
4394    fn test_take_record_batch_null_index_out_of_bounds_value() {
4395        // The value in a null index slot is never read, so it need not be in bounds
4396        let indices = UInt32Array::new(
4397            vec![2, u32::MAX, 0].into(),
4398            Some(NullBuffer::from(vec![true, false, true])),
4399        );
4400        for first in zero_width_columns(3) {
4401            let batch = batch_with_first_column(first);
4402            let taken = take_record_batch(&batch, &indices).unwrap();
4403
4404            assert_eq!(taken.num_rows(), 3);
4405            assert_eq!(
4406                taken.column(1).as_primitive::<Int32Type>(),
4407                &Int32Array::from(vec![Some(3), None, Some(1)])
4408            );
4409            assert_eq!(
4410                taken.column(2).as_string::<i32>(),
4411                &StringArray::from(vec![Some("ccc"), None, Some("a")])
4412            );
4413        }
4414    }
4415
4416    #[test]
4417    fn test_take_record_batch_empty() {
4418        let batch = batch_with_first_column(Arc::new(NullArray::new(3))).slice(0, 0);
4419
4420        let taken = take_record_batch(&batch, &UInt32Array::from(Vec::<u32>::new())).unwrap();
4421        assert_eq!(taken.num_rows(), 0);
4422        assert_eq!(taken.schema(), batch.schema());
4423
4424        let taken = take_record_batch(&batch, &UInt32Array::from(vec![None, None])).unwrap();
4425        assert_eq!(taken.num_rows(), 2);
4426        assert_eq!(taken.column(1).null_count(), 2);
4427
4428        assert!(take_record_batch(&batch, &UInt32Array::from(vec![0])).is_err());
4429    }
4430
4431    #[test]
4432    fn test_take_record_batch_no_columns() {
4433        let options = RecordBatchOptions::new().with_row_count(Some(3));
4434        let batch =
4435            RecordBatch::try_new_with_options(Arc::new(Schema::empty()), vec![], &options).unwrap();
4436
4437        let taken = take_record_batch(&batch, &UInt32Array::from(vec![2, 0, 2, 1])).unwrap();
4438        assert_eq!(taken.num_rows(), 4);
4439
4440        assert!(take_record_batch(&batch, &UInt32Array::from(vec![3])).is_err());
4441    }
4442}