Skip to main content

arrow_select/
take.rs

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