Skip to main content

arrow_cmp/
lib.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//! Basic comparator factories shared by Arrow crates that need to compare
19//! arbitrary array slots without pulling in the full `arrow-ord` crate.
20//!
21//! The only public surface is [`make_comparator`] (with [`DynComparator`] as the
22//! returned function type). `arrow-ord` re-exports both from here, so its
23//! public API is unchanged.
24//!
25//! This crate exists so that crates such as `arrow-select` can use slot-wise
26//! comparison (e.g. for the run-end-encoded `take` fast path) without taking on
27//! the full ordering kernel suite — which would either create a circular
28//! dependency (`arrow-ord` already depends on `arrow-select`) or force every
29//! downstream user of `arrow-array` to compile the comparator machinery whether
30//! they need it or not.
31
32#![deny(clippy::allow_attributes)]
33#![deny(rustdoc::broken_intra_doc_links)]
34#![warn(missing_docs)]
35
36use arrow_array::cast::AsArray;
37use arrow_array::types::*;
38use arrow_array::*;
39use arrow_buffer::{ArrowNativeType, NullBuffer};
40use arrow_schema::{ArrowError, DataType, SortOptions};
41use std::{cmp::Ordering, collections::HashMap};
42
43fn compare_run_end_encoded<R: RunEndIndexType>(
44    left: &dyn Array,
45    right: &dyn Array,
46    opts: SortOptions,
47) -> Result<DynComparator, ArrowError> {
48    let left = left.as_run::<R>();
49    let right = right.as_run::<R>();
50
51    let c_opts = child_opts(opts);
52    let cmp = make_comparator(left.values().as_ref(), right.values().as_ref(), c_opts)?;
53
54    let l_run_ends = left.run_ends().clone();
55    let r_run_ends = right.run_ends().clone();
56
57    let f = compare(left, right, opts, move |i, j| {
58        let l_physical = l_run_ends.get_physical_index(i);
59        let r_physical = r_run_ends.get_physical_index(j);
60        cmp(l_physical, r_physical)
61    });
62    Ok(f)
63}
64
65/// Compare values at arbitrary indices in two arrays.
66pub type DynComparator = Box<dyn Fn(usize, usize) -> Ordering + Send + Sync>;
67
68/// If parent sort order is descending we need to invert the value of nulls_first so that
69/// when the parent is sorted based on the produced ranks, nulls are still ordered correctly
70fn child_opts(opts: SortOptions) -> SortOptions {
71    SortOptions {
72        descending: false,
73        nulls_first: opts.nulls_first != opts.descending,
74    }
75}
76
77fn compare<A, F>(l: &A, r: &A, opts: SortOptions, cmp: F) -> DynComparator
78where
79    A: Array + Clone,
80    F: Fn(usize, usize) -> Ordering + Send + Sync + 'static,
81{
82    let l = l.logical_nulls().filter(|x| x.null_count() > 0);
83    let r = r.logical_nulls().filter(|x| x.null_count() > 0);
84    match (opts.nulls_first, opts.descending) {
85        (true, true) => compare_impl::<true, true, _>(l, r, cmp),
86        (true, false) => compare_impl::<true, false, _>(l, r, cmp),
87        (false, true) => compare_impl::<false, true, _>(l, r, cmp),
88        (false, false) => compare_impl::<false, false, _>(l, r, cmp),
89    }
90}
91
92fn compare_impl<const NULLS_FIRST: bool, const DESCENDING: bool, F>(
93    l: Option<NullBuffer>,
94    r: Option<NullBuffer>,
95    cmp: F,
96) -> DynComparator
97where
98    F: Fn(usize, usize) -> Ordering + Send + Sync + 'static,
99{
100    let cmp = move |i, j| match DESCENDING {
101        true => cmp(i, j).reverse(),
102        false => cmp(i, j),
103    };
104
105    let (left_null, right_null) = match NULLS_FIRST {
106        true => (Ordering::Less, Ordering::Greater),
107        false => (Ordering::Greater, Ordering::Less),
108    };
109
110    match (l, r) {
111        (None, None) => Box::new(cmp),
112        (Some(l), None) => Box::new(move |i, j| match l.is_null(i) {
113            true => left_null,
114            false => cmp(i, j),
115        }),
116        (None, Some(r)) => Box::new(move |i, j| match r.is_null(j) {
117            true => right_null,
118            false => cmp(i, j),
119        }),
120        (Some(l), Some(r)) => Box::new(move |i, j| match (l.is_null(i), r.is_null(j)) {
121            (true, true) => Ordering::Equal,
122            (true, false) => left_null,
123            (false, true) => right_null,
124            (false, false) => cmp(i, j),
125        }),
126    }
127}
128
129fn compare_primitive<T: ArrowPrimitiveType>(
130    left: &dyn Array,
131    right: &dyn Array,
132    opts: SortOptions,
133) -> DynComparator
134where
135    T::Native: ArrowNativeTypeOp,
136{
137    let left = left.as_primitive::<T>();
138    let right = right.as_primitive::<T>();
139    let l_values = left.values().clone();
140    let r_values = right.values().clone();
141
142    compare(&left, &right, opts, move |i, j| {
143        l_values[i].compare(r_values[j])
144    })
145}
146
147fn compare_boolean(left: &dyn Array, right: &dyn Array, opts: SortOptions) -> DynComparator {
148    let left = left.as_boolean();
149    let right = right.as_boolean();
150
151    let l_values = left.values().clone();
152    let r_values = right.values().clone();
153
154    compare(left, right, opts, move |i, j| {
155        l_values.value(i).cmp(&r_values.value(j))
156    })
157}
158
159fn compare_bytes<T: ByteArrayType>(
160    left: &dyn Array,
161    right: &dyn Array,
162    opts: SortOptions,
163) -> DynComparator {
164    let left = left.as_bytes::<T>();
165    let right = right.as_bytes::<T>();
166
167    let l = left.clone();
168    let r = right.clone();
169    compare(left, right, opts, move |i, j| {
170        let l: &[u8] = l.value(i).as_ref();
171        let r: &[u8] = r.value(j).as_ref();
172        l.cmp(r)
173    })
174}
175
176fn compare_byte_view<T: ByteViewType>(
177    left: &dyn Array,
178    right: &dyn Array,
179    opts: SortOptions,
180) -> DynComparator {
181    let left = left.as_byte_view::<T>();
182    let right = right.as_byte_view::<T>();
183
184    let l = left.clone();
185    let r = right.clone();
186    compare(left, right, opts, move |i, j| {
187        compare_byte_view_values(&l, i, &r, j)
188    })
189}
190
191fn compare_byte_view_values<T: ByteViewType>(
192    left: &GenericByteViewArray<T>,
193    left_idx: usize,
194    right: &GenericByteViewArray<T>,
195    right_idx: usize,
196) -> Ordering {
197    assert!(left_idx < left.len());
198    assert!(right_idx < right.len());
199
200    if left.data_buffers().is_empty() && right.data_buffers().is_empty() {
201        let l_view = unsafe { left.views().get_unchecked(left_idx) };
202        let r_view = unsafe { right.views().get_unchecked(right_idx) };
203        return GenericByteViewArray::<T>::inline_key_fast(*l_view)
204            .cmp(&GenericByteViewArray::<T>::inline_key_fast(*r_view));
205    }
206
207    unsafe { GenericByteViewArray::compare_unchecked(left, left_idx, right, right_idx) }
208}
209
210fn compare_dict<K: ArrowDictionaryKeyType>(
211    left: &dyn Array,
212    right: &dyn Array,
213    opts: SortOptions,
214) -> Result<DynComparator, ArrowError> {
215    let left = left.as_dictionary::<K>();
216    let right = right.as_dictionary::<K>();
217
218    let c_opts = child_opts(opts);
219    let cmp = make_comparator(left.values().as_ref(), right.values().as_ref(), c_opts)?;
220    let left_keys = left.keys().values().clone();
221    let right_keys = right.keys().values().clone();
222
223    let f = compare(left, right, opts, move |i, j| {
224        let l = left_keys[i].as_usize();
225        let r = right_keys[j].as_usize();
226        cmp(l, r)
227    });
228    Ok(f)
229}
230
231fn compare_list<O: OffsetSizeTrait>(
232    left: &dyn Array,
233    right: &dyn Array,
234    opts: SortOptions,
235) -> Result<DynComparator, ArrowError> {
236    let left = left.as_list::<O>();
237    let right = right.as_list::<O>();
238
239    let c_opts = child_opts(opts);
240    let cmp = make_comparator(left.values().as_ref(), right.values().as_ref(), c_opts)?;
241
242    let l_o = left.offsets().clone();
243    let r_o = right.offsets().clone();
244    let f = compare(left, right, opts, move |i, j| {
245        let l_end = l_o[i + 1].as_usize();
246        let l_start = l_o[i].as_usize();
247
248        let r_end = r_o[j + 1].as_usize();
249        let r_start = r_o[j].as_usize();
250
251        for (i, j) in (l_start..l_end).zip(r_start..r_end) {
252            match cmp(i, j) {
253                Ordering::Equal => continue,
254                r => return r,
255            }
256        }
257        (l_end - l_start).cmp(&(r_end - r_start))
258    });
259    Ok(f)
260}
261
262fn compare_fixed_list(
263    left: &dyn Array,
264    right: &dyn Array,
265    opts: SortOptions,
266) -> Result<DynComparator, ArrowError> {
267    let left = left.as_fixed_size_list();
268    let right = right.as_fixed_size_list();
269
270    let c_opts = child_opts(opts);
271    let cmp = make_comparator(left.values().as_ref(), right.values().as_ref(), c_opts)?;
272
273    let l_size = left.value_length().to_usize().unwrap();
274    let r_size = right.value_length().to_usize().unwrap();
275    let size_cmp = l_size.cmp(&r_size);
276
277    let f = compare(left, right, opts, move |i, j| {
278        let l_start = i * l_size;
279        let l_end = l_start + l_size;
280        let r_start = j * r_size;
281        let r_end = r_start + r_size;
282        for (i, j) in (l_start..l_end).zip(r_start..r_end) {
283            match cmp(i, j) {
284                Ordering::Equal => continue,
285                r => return r,
286            }
287        }
288        size_cmp
289    });
290    Ok(f)
291}
292
293fn compare_list_view<O: OffsetSizeTrait>(
294    left: &dyn Array,
295    right: &dyn Array,
296    opts: SortOptions,
297) -> Result<DynComparator, ArrowError> {
298    let left = left.as_list_view::<O>();
299    let right = right.as_list_view::<O>();
300
301    let c_opts = child_opts(opts);
302    let cmp = make_comparator(left.values().as_ref(), right.values().as_ref(), c_opts)?;
303
304    let l_offsets = left.offsets().clone();
305    let l_sizes = left.sizes().clone();
306    let r_offsets = right.offsets().clone();
307    let r_sizes = right.sizes().clone();
308
309    let f = compare(left, right, opts, move |i, j| {
310        let l_start = l_offsets[i].as_usize();
311        let l_len = l_sizes[i].as_usize();
312        let l_end = l_start + l_len;
313
314        let r_start = r_offsets[j].as_usize();
315        let r_len = r_sizes[j].as_usize();
316        let r_end = r_start + r_len;
317
318        for (i, j) in (l_start..l_end).zip(r_start..r_end) {
319            match cmp(i, j) {
320                Ordering::Equal => continue,
321                r => return r,
322            }
323        }
324        l_len.cmp(&r_len)
325    });
326    Ok(f)
327}
328
329fn compare_map(
330    left: &dyn Array,
331    right: &dyn Array,
332    opts: SortOptions,
333) -> Result<DynComparator, ArrowError> {
334    let left = left.as_map();
335    let right = right.as_map();
336
337    let c_opts = child_opts(opts);
338    let cmp = make_comparator(left.entries(), right.entries(), c_opts)?;
339
340    let l_o = left.offsets().clone();
341    let r_o = right.offsets().clone();
342    let f = compare(left, right, opts, move |i, j| {
343        let l_end = l_o[i + 1].as_usize();
344        let l_start = l_o[i].as_usize();
345
346        let r_end = r_o[j + 1].as_usize();
347        let r_start = r_o[j].as_usize();
348
349        for (i, j) in (l_start..l_end).zip(r_start..r_end) {
350            match cmp(i, j) {
351                Ordering::Equal => continue,
352                r => return r,
353            }
354        }
355        (l_end - l_start).cmp(&(r_end - r_start))
356    });
357    Ok(f)
358}
359
360fn compare_struct(
361    left: &dyn Array,
362    right: &dyn Array,
363    opts: SortOptions,
364) -> Result<DynComparator, ArrowError> {
365    let left = left.as_struct();
366    let right = right.as_struct();
367
368    if left.columns().len() != right.columns().len() {
369        return Err(ArrowError::InvalidArgumentError(
370            "Cannot compare StructArray with different number of columns".to_string(),
371        ));
372    }
373
374    let c_opts = child_opts(opts);
375    let columns = left.columns().iter().zip(right.columns());
376    let comparators = columns
377        .map(|(l, r)| make_comparator(l, r, c_opts))
378        .collect::<Result<Vec<_>, _>>()?;
379
380    let f = compare(left, right, opts, move |i, j| {
381        for cmp in &comparators {
382            match cmp(i, j) {
383                Ordering::Equal => continue,
384                r => return r,
385            }
386        }
387        Ordering::Equal
388    });
389    Ok(f)
390}
391
392fn compare_union(
393    left: &dyn Array,
394    right: &dyn Array,
395    opts: SortOptions,
396) -> Result<DynComparator, ArrowError> {
397    let left = left.as_union();
398    let right = right.as_union();
399
400    let (left_fields, left_mode) = match left.data_type() {
401        DataType::Union(fields, mode) => (fields, mode),
402        _ => unreachable!(),
403    };
404    let (right_fields, right_mode) = match right.data_type() {
405        DataType::Union(fields, mode) => (fields, mode),
406        _ => unreachable!(),
407    };
408
409    if left_fields != right_fields {
410        return Err(ArrowError::InvalidArgumentError(format!(
411            "Cannot compare UnionArrays with different fields: left={left_fields:?}, right={right_fields:?}"
412        )));
413    }
414
415    if left_mode != right_mode {
416        return Err(ArrowError::InvalidArgumentError(format!(
417            "Cannot compare UnionArrays with different modes: left={left_mode:?}, right={right_mode:?}"
418        )));
419    }
420
421    let c_opts = child_opts(opts);
422
423    let mut field_comparators = HashMap::with_capacity(left_fields.len());
424
425    for (type_id, _field) in left_fields.iter() {
426        let left_child = left.child(type_id);
427        let right_child = right.child(type_id);
428        let cmp = make_comparator(left_child.as_ref(), right_child.as_ref(), c_opts)?;
429
430        field_comparators.insert(type_id, cmp);
431    }
432
433    let left_type_ids = left.type_ids().clone();
434    let right_type_ids = right.type_ids().clone();
435
436    let left_offsets = left.offsets().cloned();
437    let right_offsets = right.offsets().cloned();
438
439    let f = compare(left, right, opts, move |i, j| {
440        let left_type_id = left_type_ids[i];
441        let right_type_id = right_type_ids[j];
442
443        match left_type_id.cmp(&right_type_id) {
444            Ordering::Equal => {
445                let left_offset = left_offsets.as_ref().map(|o| o[i] as usize).unwrap_or(i);
446                let right_offset = right_offsets.as_ref().map(|o| o[j] as usize).unwrap_or(j);
447
448                let cmp = field_comparators
449                    .get(&left_type_id)
450                    .expect("type id not found in field_comparators");
451
452                cmp(left_offset, right_offset)
453            }
454            other => other,
455        }
456    });
457    Ok(f)
458}
459
460/// Returns a comparison function that compares two values at two arbitrary indices.
461///
462/// If `nulls_first` is true, null values are considered less than any non-null
463/// value; otherwise they are considered greater. This is primarily shared by
464/// crates that need repeated slot comparisons without constructing sliced arrays.
465pub fn make_comparator(
466    left: &dyn Array,
467    right: &dyn Array,
468    opts: SortOptions,
469) -> Result<DynComparator, ArrowError> {
470    use arrow_schema::DataType::*;
471
472    macro_rules! primitive_helper {
473        ($t:ty, $left:expr, $right:expr, $nulls_first:expr) => {
474            Ok(compare_primitive::<$t>($left, $right, $nulls_first))
475        };
476    }
477    downcast_primitive! {
478        left.data_type(), right.data_type() => (primitive_helper, left, right, opts),
479        (Boolean, Boolean) => Ok(compare_boolean(left, right, opts)),
480        (Utf8, Utf8) => Ok(compare_bytes::<Utf8Type>(left, right, opts)),
481        (LargeUtf8, LargeUtf8) => Ok(compare_bytes::<LargeUtf8Type>(left, right, opts)),
482        (Utf8View, Utf8View) => Ok(compare_byte_view::<StringViewType>(left, right, opts)),
483        (Binary, Binary) => Ok(compare_bytes::<BinaryType>(left, right, opts)),
484        (LargeBinary, LargeBinary) => Ok(compare_bytes::<LargeBinaryType>(left, right, opts)),
485        (BinaryView, BinaryView) => Ok(compare_byte_view::<BinaryViewType>(left, right, opts)),
486        (FixedSizeBinary(_), FixedSizeBinary(_)) => {
487            let left = left.as_fixed_size_binary();
488            let right = right.as_fixed_size_binary();
489
490            let l = left.clone();
491            let r = right.clone();
492            Ok(compare(left, right, opts, move |i, j| {
493                l.value(i).cmp(r.value(j))
494            }))
495        },
496        (List(_), List(_)) => compare_list::<i32>(left, right, opts),
497        (LargeList(_), LargeList(_)) => compare_list::<i64>(left, right, opts),
498        (ListView(_), ListView(_)) => compare_list_view::<i32>(left, right, opts),
499        (LargeListView(_), LargeListView(_)) => compare_list_view::<i64>(left, right, opts),
500        (FixedSizeList(_, _), FixedSizeList(_, _)) => compare_fixed_list(left, right, opts),
501        (Struct(_), Struct(_)) => compare_struct(left, right, opts),
502        (Dictionary(l_key, _), Dictionary(r_key, _)) => {
503             macro_rules! dict_helper {
504                ($t:ty, $left:expr, $right:expr, $opts: expr) => {
505                     compare_dict::<$t>($left, $right, $opts)
506                 };
507             }
508            downcast_integer! {
509                 l_key.as_ref(), r_key.as_ref() => (dict_helper, left, right, opts),
510                 _ => unreachable!()
511             }
512        },
513        (RunEndEncoded(l_run_ends, _), RunEndEncoded(r_run_ends, _)) => {
514            macro_rules! run_end_helper {
515                ($t:ty, $left:expr, $right:expr, $opts:expr) => {
516                    compare_run_end_encoded::<$t>($left, $right, $opts)
517                };
518            }
519            downcast_run_end_index! {
520                l_run_ends.data_type(), r_run_ends.data_type() => (run_end_helper, left, right, opts),
521                _ => Err(ArrowError::InvalidArgumentError(format!(
522                    "Cannot compare RunEndEncoded arrays with different run ends types: left={:?}, right={:?}",
523                    l_run_ends.data_type(),
524                    r_run_ends.data_type()
525                )))
526            }
527        },
528        (Map(_, _), Map(_, _)) => compare_map(left, right, opts),
529        (Null, Null) => Ok(Box::new(|_, _| Ordering::Equal)),
530        (Union(_, _), Union(_, _)) => compare_union(left, right, opts),
531        (lhs, rhs) => Err(ArrowError::InvalidArgumentError(match lhs == rhs {
532            true => format!("The data type type {lhs:?} has no natural order"),
533            false => "Can't compare arrays of different types".to_string(),
534        }))
535    }
536}
537
538#[cfg(test)]
539mod tests {
540    use super::*;
541    use arrow_array::builder::{Int32Builder, ListBuilder, MapBuilder, StringBuilder};
542    use arrow_buffer::{IntervalDayTime, NullBuffer, OffsetBuffer, ScalarBuffer, i256};
543    use arrow_schema::{ArrowError, DataType, Field, Fields, UnionFields};
544    use half::f16;
545    use std::cmp::Ordering;
546    use std::sync::Arc;
547
548    #[test]
549    fn test_fixed_size_binary() {
550        let items = vec![vec![1u8], vec![2u8]];
551        let array = FixedSizeBinaryArray::try_from_iter(items.into_iter()).unwrap();
552
553        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
554
555        assert_eq!(Ordering::Less, cmp(0, 1));
556    }
557
558    #[test]
559    fn test_fixed_size_binary_fixed_size_binary() {
560        let items = vec![vec![1u8]];
561        let array1 = FixedSizeBinaryArray::try_from_iter(items.into_iter()).unwrap();
562        let items = vec![vec![2u8]];
563        let array2 = FixedSizeBinaryArray::try_from_iter(items.into_iter()).unwrap();
564
565        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
566
567        assert_eq!(Ordering::Less, cmp(0, 0));
568    }
569
570    #[test]
571    fn test_i32() {
572        let array = Int32Array::from(vec![1, 2]);
573
574        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
575
576        assert_eq!(Ordering::Less, (cmp)(0, 1));
577    }
578
579    #[test]
580    fn test_i32_i32() {
581        let array1 = Int32Array::from(vec![1]);
582        let array2 = Int32Array::from(vec![2]);
583
584        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
585
586        assert_eq!(Ordering::Less, cmp(0, 0));
587    }
588
589    #[cfg_attr(miri, ignore)] // Unsupported inline assembly
590    #[test]
591    fn test_f16() {
592        let array = Float16Array::from(vec![f16::from_f32(1.0), f16::from_f32(2.0)]);
593
594        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
595
596        assert_eq!(Ordering::Less, cmp(0, 1));
597    }
598
599    #[test]
600    fn test_f64() {
601        let array = Float64Array::from(vec![1.0, 2.0]);
602
603        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
604
605        assert_eq!(Ordering::Less, cmp(0, 1));
606    }
607
608    #[test]
609    fn test_f64_nan() {
610        let array = Float64Array::from(vec![1.0, f64::NAN]);
611
612        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
613
614        assert_eq!(Ordering::Less, cmp(0, 1));
615        assert_eq!(Ordering::Equal, cmp(1, 1));
616    }
617
618    #[test]
619    fn test_f64_zeros() {
620        let array = Float64Array::from(vec![-0.0, 0.0]);
621
622        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
623
624        assert_eq!(Ordering::Less, cmp(0, 1));
625        assert_eq!(Ordering::Greater, cmp(1, 0));
626    }
627
628    #[test]
629    fn test_interval_day_time() {
630        let array = IntervalDayTimeArray::from(vec![
631            // 0 days, 1 second
632            IntervalDayTimeType::make_value(0, 1000),
633            // 1 day, 2 milliseconds
634            IntervalDayTimeType::make_value(1, 2),
635            // 90M milliseconds (which is more than is in 1 day)
636            IntervalDayTimeType::make_value(0, 90_000_000),
637        ]);
638
639        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
640
641        assert_eq!(Ordering::Less, cmp(0, 1));
642        assert_eq!(Ordering::Greater, cmp(1, 0));
643
644        // somewhat confusingly, while 90M milliseconds is more than 1 day,
645        // it will compare less as the comparison is done on the underlying
646        // values not field by field
647        assert_eq!(Ordering::Greater, cmp(1, 2));
648        assert_eq!(Ordering::Less, cmp(2, 1));
649    }
650
651    #[test]
652    fn test_interval_year_month() {
653        let array = IntervalYearMonthArray::from(vec![
654            // 1 year, 0 months
655            IntervalYearMonthType::make_value(1, 0),
656            // 0 years, 13 months
657            IntervalYearMonthType::make_value(0, 13),
658            // 1 year, 1 month
659            IntervalYearMonthType::make_value(1, 1),
660        ]);
661
662        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
663
664        assert_eq!(Ordering::Less, cmp(0, 1));
665        assert_eq!(Ordering::Greater, cmp(1, 0));
666
667        // the underlying representation is months, so both quantities are the same
668        assert_eq!(Ordering::Equal, cmp(1, 2));
669        assert_eq!(Ordering::Equal, cmp(2, 1));
670    }
671
672    #[test]
673    fn test_interval_month_day_nano() {
674        let array = IntervalMonthDayNanoArray::from(vec![
675            // 100 days
676            IntervalMonthDayNanoType::make_value(0, 100, 0),
677            // 1 month
678            IntervalMonthDayNanoType::make_value(1, 0, 0),
679            // 100 day, 1 nanoseconds
680            IntervalMonthDayNanoType::make_value(0, 100, 2),
681        ]);
682
683        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
684
685        assert_eq!(Ordering::Less, cmp(0, 1));
686        assert_eq!(Ordering::Greater, cmp(1, 0));
687
688        // somewhat confusingly, while 100 days is more than 1 month in all cases
689        // it will compare less as the comparison is done on the underlying
690        // values not field by field
691        assert_eq!(Ordering::Greater, cmp(1, 2));
692        assert_eq!(Ordering::Less, cmp(2, 1));
693    }
694
695    #[test]
696    fn test_decimali32() {
697        let array = vec![Some(5_i32), Some(2_i32), Some(3_i32)]
698            .into_iter()
699            .collect::<Decimal32Array>()
700            .with_precision_and_scale(8, 6)
701            .unwrap();
702
703        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
704        assert_eq!(Ordering::Less, cmp(1, 0));
705        assert_eq!(Ordering::Greater, cmp(0, 2));
706    }
707
708    #[test]
709    fn test_decimali64() {
710        let array = vec![Some(5_i64), Some(2_i64), Some(3_i64)]
711            .into_iter()
712            .collect::<Decimal64Array>()
713            .with_precision_and_scale(16, 6)
714            .unwrap();
715
716        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
717        assert_eq!(Ordering::Less, cmp(1, 0));
718        assert_eq!(Ordering::Greater, cmp(0, 2));
719    }
720
721    #[test]
722    fn test_decimali128() {
723        let array = vec![Some(5_i128), Some(2_i128), Some(3_i128)]
724            .into_iter()
725            .collect::<Decimal128Array>()
726            .with_precision_and_scale(23, 6)
727            .unwrap();
728
729        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
730        assert_eq!(Ordering::Less, cmp(1, 0));
731        assert_eq!(Ordering::Greater, cmp(0, 2));
732    }
733
734    #[test]
735    fn test_decimali256() {
736        let array = vec![
737            Some(i256::from_i128(5_i128)),
738            Some(i256::from_i128(2_i128)),
739            Some(i256::from_i128(3_i128)),
740        ]
741        .into_iter()
742        .collect::<Decimal256Array>()
743        .with_precision_and_scale(53, 6)
744        .unwrap();
745
746        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
747        assert_eq!(Ordering::Less, cmp(1, 0));
748        assert_eq!(Ordering::Greater, cmp(0, 2));
749    }
750
751    #[test]
752    fn test_dict() {
753        let data = vec!["a", "b", "c", "a", "a", "c", "c"];
754        let array = data.into_iter().collect::<DictionaryArray<Int16Type>>();
755
756        let cmp = make_comparator(&array, &array, SortOptions::default()).unwrap();
757
758        assert_eq!(Ordering::Less, cmp(0, 1));
759        assert_eq!(Ordering::Equal, cmp(3, 4));
760        assert_eq!(Ordering::Greater, cmp(2, 3));
761    }
762
763    #[test]
764    fn test_multiple_dict() {
765        let d1 = vec!["a", "b", "c", "d"];
766        let a1 = d1.into_iter().collect::<DictionaryArray<Int16Type>>();
767        let d2 = vec!["e", "f", "g", "a"];
768        let a2 = d2.into_iter().collect::<DictionaryArray<Int16Type>>();
769
770        let cmp = make_comparator(&a1, &a2, SortOptions::default()).unwrap();
771
772        assert_eq!(Ordering::Less, cmp(0, 0));
773        assert_eq!(Ordering::Equal, cmp(0, 3));
774        assert_eq!(Ordering::Greater, cmp(1, 3));
775    }
776
777    #[test]
778    fn test_primitive_dict() {
779        let values = Int32Array::from(vec![1_i32, 0, 2, 5]);
780        let keys = Int8Array::from_iter_values([0, 0, 1, 3]);
781        let array1 = DictionaryArray::new(keys, Arc::new(values));
782
783        let values = Int32Array::from(vec![2_i32, 3, 4, 5]);
784        let keys = Int8Array::from_iter_values([0, 1, 1, 3]);
785        let array2 = DictionaryArray::new(keys, Arc::new(values));
786
787        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
788
789        assert_eq!(Ordering::Less, cmp(0, 0));
790        assert_eq!(Ordering::Less, cmp(0, 3));
791        assert_eq!(Ordering::Equal, cmp(3, 3));
792        assert_eq!(Ordering::Greater, cmp(3, 1));
793        assert_eq!(Ordering::Greater, cmp(3, 2));
794    }
795
796    #[test]
797    fn test_float_dict() {
798        let values = Float32Array::from(vec![1.0, 0.5, 2.1, 5.5]);
799        let keys = Int8Array::from_iter_values([0, 0, 1, 3]);
800        let array1 = DictionaryArray::try_new(keys, Arc::new(values)).unwrap();
801
802        let values = Float32Array::from(vec![1.2, 3.2, 4.0, 5.5]);
803        let keys = Int8Array::from_iter_values([0, 1, 1, 3]);
804        let array2 = DictionaryArray::new(keys, Arc::new(values));
805
806        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
807
808        assert_eq!(Ordering::Less, cmp(0, 0));
809        assert_eq!(Ordering::Less, cmp(0, 3));
810        assert_eq!(Ordering::Equal, cmp(3, 3));
811        assert_eq!(Ordering::Greater, cmp(3, 1));
812        assert_eq!(Ordering::Greater, cmp(3, 2));
813    }
814
815    #[test]
816    fn test_timestamp_dict() {
817        let values = TimestampSecondArray::from(vec![1, 0, 2, 5]);
818        let keys = Int8Array::from_iter_values([0, 0, 1, 3]);
819        let array1 = DictionaryArray::new(keys, Arc::new(values));
820
821        let values = TimestampSecondArray::from(vec![2, 3, 4, 5]);
822        let keys = Int8Array::from_iter_values([0, 1, 1, 3]);
823        let array2 = DictionaryArray::new(keys, Arc::new(values));
824
825        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
826
827        assert_eq!(Ordering::Less, cmp(0, 0));
828        assert_eq!(Ordering::Less, cmp(0, 3));
829        assert_eq!(Ordering::Equal, cmp(3, 3));
830        assert_eq!(Ordering::Greater, cmp(3, 1));
831        assert_eq!(Ordering::Greater, cmp(3, 2));
832    }
833
834    #[test]
835    fn test_interval_dict() {
836        let v1 = IntervalDayTime::new(0, 1);
837        let v2 = IntervalDayTime::new(0, 2);
838        let v3 = IntervalDayTime::new(12, 2);
839
840        let values = IntervalDayTimeArray::from(vec![Some(v1), Some(v2), None, Some(v3)]);
841        let keys = Int8Array::from_iter_values([0, 0, 1, 3]);
842        let array1 = DictionaryArray::new(keys, Arc::new(values));
843
844        let values = IntervalDayTimeArray::from(vec![Some(v3), Some(v2), None, Some(v1)]);
845        let keys = Int8Array::from_iter_values([0, 1, 1, 3]);
846        let array2 = DictionaryArray::new(keys, Arc::new(values));
847
848        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
849
850        assert_eq!(Ordering::Less, cmp(0, 0)); // v1 vs v3
851        assert_eq!(Ordering::Equal, cmp(0, 3)); // v1 vs v1
852        assert_eq!(Ordering::Greater, cmp(3, 3)); // v3 vs v1
853        assert_eq!(Ordering::Greater, cmp(3, 1)); // v3 vs v2
854        assert_eq!(Ordering::Greater, cmp(3, 2)); // v3 vs v2
855    }
856
857    #[test]
858    fn test_duration_dict() {
859        let values = DurationSecondArray::from(vec![1, 0, 2, 5]);
860        let keys = Int8Array::from_iter_values([0, 0, 1, 3]);
861        let array1 = DictionaryArray::new(keys, Arc::new(values));
862
863        let values = DurationSecondArray::from(vec![2, 3, 4, 5]);
864        let keys = Int8Array::from_iter_values([0, 1, 1, 3]);
865        let array2 = DictionaryArray::new(keys, Arc::new(values));
866
867        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
868
869        assert_eq!(Ordering::Less, cmp(0, 0));
870        assert_eq!(Ordering::Less, cmp(0, 3));
871        assert_eq!(Ordering::Equal, cmp(3, 3));
872        assert_eq!(Ordering::Greater, cmp(3, 1));
873        assert_eq!(Ordering::Greater, cmp(3, 2));
874    }
875
876    #[test]
877    fn test_decimal_dict() {
878        let values = Decimal128Array::from(vec![1, 0, 2, 5]);
879        let keys = Int8Array::from_iter_values([0, 0, 1, 3]);
880        let array1 = DictionaryArray::new(keys, Arc::new(values));
881
882        let values = Decimal128Array::from(vec![2, 3, 4, 5]);
883        let keys = Int8Array::from_iter_values([0, 1, 1, 3]);
884        let array2 = DictionaryArray::new(keys, Arc::new(values));
885
886        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
887
888        assert_eq!(Ordering::Less, cmp(0, 0));
889        assert_eq!(Ordering::Less, cmp(0, 3));
890        assert_eq!(Ordering::Equal, cmp(3, 3));
891        assert_eq!(Ordering::Greater, cmp(3, 1));
892        assert_eq!(Ordering::Greater, cmp(3, 2));
893    }
894
895    #[test]
896    fn test_decimal256_dict() {
897        let values = Decimal256Array::from(vec![
898            i256::from_i128(1),
899            i256::from_i128(0),
900            i256::from_i128(2),
901            i256::from_i128(5),
902        ]);
903        let keys = Int8Array::from_iter_values([0, 0, 1, 3]);
904        let array1 = DictionaryArray::new(keys, Arc::new(values));
905
906        let values = Decimal256Array::from(vec![
907            i256::from_i128(2),
908            i256::from_i128(3),
909            i256::from_i128(4),
910            i256::from_i128(5),
911        ]);
912        let keys = Int8Array::from_iter_values([0, 1, 1, 3]);
913        let array2 = DictionaryArray::new(keys, Arc::new(values));
914
915        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
916
917        assert_eq!(Ordering::Less, cmp(0, 0));
918        assert_eq!(Ordering::Less, cmp(0, 3));
919        assert_eq!(Ordering::Equal, cmp(3, 3));
920        assert_eq!(Ordering::Greater, cmp(3, 1));
921        assert_eq!(Ordering::Greater, cmp(3, 2));
922    }
923
924    fn test_bytes_impl<T: ByteArrayType>() {
925        let offsets = OffsetBuffer::from_lengths([3, 3, 1]);
926        let a = GenericByteArray::<T>::new(offsets, b"abcdefa".into(), None);
927        let cmp = make_comparator(&a, &a, SortOptions::default()).unwrap();
928
929        assert_eq!(Ordering::Less, cmp(0, 1));
930        assert_eq!(Ordering::Greater, cmp(0, 2));
931        assert_eq!(Ordering::Equal, cmp(1, 1));
932    }
933
934    #[test]
935    fn test_bytes() {
936        test_bytes_impl::<Utf8Type>();
937        test_bytes_impl::<LargeUtf8Type>();
938        test_bytes_impl::<BinaryType>();
939        test_bytes_impl::<LargeBinaryType>();
940    }
941
942    fn assert_cmp_cases<A: Array>(
943        array1: &A,
944        array2: &A,
945        opts: SortOptions,
946        cases: &[(usize, usize, Ordering)],
947    ) {
948        let cmp = make_comparator(array1, array2, opts).unwrap();
949        for (left, right, expected) in cases {
950            assert_eq!(cmp(*left, *right), *expected);
951        }
952    }
953
954    #[test]
955    fn test_lists() {
956        let mut a = ListBuilder::new(ListBuilder::new(Int32Builder::new()));
957        a.extend([
958            Some(vec![Some(vec![Some(1), Some(2), None]), Some(vec![None])]),
959            Some(vec![
960                Some(vec![Some(1), Some(2), Some(3)]),
961                Some(vec![Some(1)]),
962            ]),
963            Some(vec![]),
964        ]);
965        let a = a.finish();
966        let mut b = ListBuilder::new(ListBuilder::new(Int32Builder::new()));
967        b.extend([
968            Some(vec![Some(vec![Some(1), Some(2), None]), Some(vec![None])]),
969            Some(vec![
970                Some(vec![Some(1), Some(2), None]),
971                Some(vec![Some(1)]),
972            ]),
973            Some(vec![
974                Some(vec![Some(1), Some(2), Some(3), Some(4)]),
975                Some(vec![Some(1)]),
976            ]),
977            None,
978        ]);
979        let b = b.finish();
980
981        // Ascending with nulls first.
982        assert_cmp_cases(
983            &a,
984            &b,
985            SortOptions {
986                descending: false,
987                nulls_first: true,
988            },
989            &[
990                (0, 0, Ordering::Equal),
991                (0, 1, Ordering::Less),
992                (0, 2, Ordering::Less),
993                (1, 2, Ordering::Less),
994                (1, 3, Ordering::Greater),
995                (2, 0, Ordering::Less),
996            ],
997        );
998
999        // Descending with nulls first.
1000        assert_cmp_cases(
1001            &a,
1002            &b,
1003            SortOptions {
1004                descending: true,
1005                nulls_first: true,
1006            },
1007            &[
1008                (0, 0, Ordering::Equal),
1009                (0, 1, Ordering::Less),
1010                (0, 2, Ordering::Less),
1011                (1, 2, Ordering::Greater),
1012                (1, 3, Ordering::Greater),
1013                (2, 0, Ordering::Greater),
1014            ],
1015        );
1016
1017        // Descending with nulls last.
1018        assert_cmp_cases(
1019            &a,
1020            &b,
1021            SortOptions {
1022                descending: true,
1023                nulls_first: false,
1024            },
1025            &[
1026                (0, 0, Ordering::Equal),
1027                (0, 1, Ordering::Greater),
1028                (0, 2, Ordering::Greater),
1029                (1, 2, Ordering::Greater),
1030                (1, 3, Ordering::Less),
1031                (2, 0, Ordering::Greater),
1032            ],
1033        );
1034
1035        // Ascending with nulls last.
1036        assert_cmp_cases(
1037            &a,
1038            &b,
1039            SortOptions {
1040                descending: false,
1041                nulls_first: false,
1042            },
1043            &[
1044                (0, 0, Ordering::Equal),
1045                (0, 1, Ordering::Greater),
1046                (0, 2, Ordering::Greater),
1047                (1, 2, Ordering::Less),
1048                (1, 3, Ordering::Less),
1049                (2, 0, Ordering::Less),
1050            ],
1051        );
1052    }
1053
1054    fn list_view_array<O: OffsetSizeTrait>(
1055        values: Vec<i32>,
1056        offsets: &[usize],
1057        sizes: &[usize],
1058        valid: Option<&[bool]>,
1059    ) -> GenericListViewArray<O> {
1060        let offsets = offsets
1061            .iter()
1062            .map(|v| O::from_usize(*v).unwrap())
1063            .collect::<ScalarBuffer<O>>();
1064        let sizes = sizes
1065            .iter()
1066            .map(|v| O::from_usize(*v).unwrap())
1067            .collect::<ScalarBuffer<O>>();
1068        let field = Arc::new(Field::new_list_field(DataType::Int32, true));
1069        let values = Int32Array::from(values);
1070        let nulls = valid.map(NullBuffer::from);
1071        GenericListViewArray::new(field, offsets, sizes, Arc::new(values), nulls)
1072    }
1073
1074    fn test_list_view_comparisons<O: OffsetSizeTrait>() {
1075        let array = list_view_array::<O>(
1076            vec![1, 2, 3, 4, 5],
1077            &[0, 2, 1, 0, 3],
1078            &[2, 2, 2, 0, 2],
1079            Some(&[true, true, true, true, false]),
1080        );
1081
1082        // Ascending with nulls first (non-monotonic offsets and empty list).
1083        assert_cmp_cases(
1084            &array,
1085            &array,
1086            SortOptions {
1087                descending: false,
1088                nulls_first: true,
1089            },
1090            &[
1091                (0, 2, Ordering::Less),    // [1,2] < [2,3]
1092                (1, 2, Ordering::Greater), // [3,4] > [2,3]
1093                (3, 0, Ordering::Less),    // [] < [1,2]
1094                (4, 0, Ordering::Less),    // null < [1,2]
1095            ],
1096        );
1097
1098        // Ascending with nulls last.
1099        assert_cmp_cases(
1100            &array,
1101            &array,
1102            SortOptions {
1103                descending: false,
1104                nulls_first: false,
1105            },
1106            &[
1107                (0, 2, Ordering::Less),
1108                (1, 2, Ordering::Greater),
1109                (3, 0, Ordering::Less),
1110                (4, 0, Ordering::Greater), // null last
1111            ],
1112        );
1113
1114        // Descending with nulls first.
1115        assert_cmp_cases(
1116            &array,
1117            &array,
1118            SortOptions {
1119                descending: true,
1120                nulls_first: true,
1121            },
1122            &[
1123                (0, 2, Ordering::Greater),
1124                (1, 2, Ordering::Less),
1125                (3, 0, Ordering::Greater),
1126                (4, 0, Ordering::Less),
1127            ],
1128        );
1129
1130        // Descending with nulls last.
1131        assert_cmp_cases(
1132            &array,
1133            &array,
1134            SortOptions {
1135                descending: true,
1136                nulls_first: false,
1137            },
1138            &[
1139                (0, 2, Ordering::Greater),
1140                (1, 2, Ordering::Less),
1141                (3, 0, Ordering::Greater),
1142                (4, 0, Ordering::Greater),
1143            ],
1144        );
1145    }
1146
1147    #[test]
1148    fn test_list_view() {
1149        test_list_view_comparisons::<i32>();
1150    }
1151
1152    #[test]
1153    fn test_large_list_view() {
1154        test_list_view_comparisons::<i64>();
1155    }
1156
1157    #[test]
1158    fn test_struct() {
1159        let fields = Fields::from(vec![
1160            Field::new("a", DataType::Int32, true),
1161            Field::new_list("b", Field::new_list_field(DataType::Int32, true), true),
1162        ]);
1163
1164        let a = Int32Array::from(vec![Some(1), Some(2), None, None]);
1165        let mut b = ListBuilder::new(Int32Builder::new());
1166        b.extend([Some(vec![Some(1), Some(2)]), Some(vec![None]), None, None]);
1167        let b = b.finish();
1168
1169        let nulls = Some(NullBuffer::from_iter([true, true, true, false]));
1170        let values = vec![Arc::new(a) as _, Arc::new(b) as _];
1171        let s1 = StructArray::new(fields.clone(), values, nulls);
1172
1173        let a = Int32Array::from(vec![None, Some(2), None]);
1174        let mut b = ListBuilder::new(Int32Builder::new());
1175        b.extend([None, None, Some(vec![])]);
1176        let b = b.finish();
1177
1178        let values = vec![Arc::new(a) as _, Arc::new(b) as _];
1179        let s2 = StructArray::new(fields.clone(), values, None);
1180
1181        let opts = SortOptions {
1182            descending: false,
1183            nulls_first: true,
1184        };
1185        let cmp = make_comparator(&s1, &s2, opts).unwrap();
1186        assert_eq!(cmp(0, 1), Ordering::Less); // (1, [1, 2]) cmp (2, None)
1187        assert_eq!(cmp(0, 0), Ordering::Greater); // (1, [1, 2]) cmp (None, None)
1188        assert_eq!(cmp(1, 1), Ordering::Greater); // (2, [None]) cmp (2, None)
1189        assert_eq!(cmp(2, 2), Ordering::Less); // (None, None) cmp (None, [])
1190        assert_eq!(cmp(3, 0), Ordering::Less); // None cmp (None, [])
1191        assert_eq!(cmp(2, 0), Ordering::Equal); // (None, None) cmp (None, None)
1192        assert_eq!(cmp(3, 0), Ordering::Less); // None cmp (None, None)
1193
1194        let opts = SortOptions {
1195            descending: true,
1196            nulls_first: true,
1197        };
1198        let cmp = make_comparator(&s1, &s2, opts).unwrap();
1199        assert_eq!(cmp(0, 1), Ordering::Greater); // (1, [1, 2]) cmp (2, None)
1200        assert_eq!(cmp(0, 0), Ordering::Greater); // (1, [1, 2]) cmp (None, None)
1201        assert_eq!(cmp(1, 1), Ordering::Greater); // (2, [None]) cmp (2, None)
1202        assert_eq!(cmp(2, 2), Ordering::Less); // (None, None) cmp (None, [])
1203        assert_eq!(cmp(3, 0), Ordering::Less); // None cmp (None, [])
1204        assert_eq!(cmp(2, 0), Ordering::Equal); // (None, None) cmp (None, None)
1205        assert_eq!(cmp(3, 0), Ordering::Less); // None cmp (None, None)
1206
1207        let opts = SortOptions {
1208            descending: true,
1209            nulls_first: false,
1210        };
1211        let cmp = make_comparator(&s1, &s2, opts).unwrap();
1212        assert_eq!(cmp(0, 1), Ordering::Greater); // (1, [1, 2]) cmp (2, None)
1213        assert_eq!(cmp(0, 0), Ordering::Less); // (1, [1, 2]) cmp (None, None)
1214        assert_eq!(cmp(1, 1), Ordering::Less); // (2, [None]) cmp (2, None)
1215        assert_eq!(cmp(2, 2), Ordering::Greater); // (None, None) cmp (None, [])
1216        assert_eq!(cmp(3, 0), Ordering::Greater); // None cmp (None, [])
1217        assert_eq!(cmp(2, 0), Ordering::Equal); // (None, None) cmp (None, None)
1218        assert_eq!(cmp(3, 0), Ordering::Greater); // None cmp (None, None)
1219
1220        let opts = SortOptions {
1221            descending: false,
1222            nulls_first: false,
1223        };
1224        let cmp = make_comparator(&s1, &s2, opts).unwrap();
1225        assert_eq!(cmp(0, 1), Ordering::Less); // (1, [1, 2]) cmp (2, None)
1226        assert_eq!(cmp(0, 0), Ordering::Less); // (1, [1, 2]) cmp (None, None)
1227        assert_eq!(cmp(1, 1), Ordering::Less); // (2, [None]) cmp (2, None)
1228        assert_eq!(cmp(2, 2), Ordering::Greater); // (None, None) cmp (None, [])
1229        assert_eq!(cmp(3, 0), Ordering::Greater); // None cmp (None, [])
1230        assert_eq!(cmp(2, 0), Ordering::Equal); // (None, None) cmp (None, None)
1231        assert_eq!(cmp(3, 0), Ordering::Greater); // None cmp (None, None)
1232    }
1233
1234    #[test]
1235    fn test_map() {
1236        // Create first map array demonstrating key priority over values:
1237        // [{"a": 100, "b": 1}, {"b": 999, "c": 1}, {}, {"x": 1}]
1238        let string_builder = StringBuilder::new();
1239        let int_builder = Int32Builder::new();
1240        let mut map1_builder = MapBuilder::new(None, string_builder, int_builder);
1241
1242        // {"a": 100, "b": 1} - high value for "a", low value for "b"
1243        map1_builder.keys().append_value("a");
1244        map1_builder.values().append_value(100);
1245        map1_builder.keys().append_value("b");
1246        map1_builder.values().append_value(1);
1247        map1_builder.append(true).unwrap();
1248
1249        // {"b": 999, "c": 1} - very high value for "b", low value for "c"
1250        map1_builder.keys().append_value("b");
1251        map1_builder.values().append_value(999);
1252        map1_builder.keys().append_value("c");
1253        map1_builder.values().append_value(1);
1254        map1_builder.append(true).unwrap();
1255
1256        // {}
1257        map1_builder.append(true).unwrap();
1258
1259        // {"x": 1}
1260        map1_builder.keys().append_value("x");
1261        map1_builder.values().append_value(1);
1262        map1_builder.append(true).unwrap();
1263
1264        let map1 = map1_builder.finish();
1265
1266        // Create second map array:
1267        // [{"a": 1, "c": 999}, {"b": 1, "d": 999}, {"a": 1}, None]
1268        let string_builder = StringBuilder::new();
1269        let int_builder = Int32Builder::new();
1270        let mut map2_builder = MapBuilder::new(None, string_builder, int_builder);
1271
1272        // {"a": 1, "c": 999} - low value for "a", high value for "c"
1273        map2_builder.keys().append_value("a");
1274        map2_builder.values().append_value(1);
1275        map2_builder.keys().append_value("c");
1276        map2_builder.values().append_value(999);
1277        map2_builder.append(true).unwrap();
1278
1279        // {"b": 1, "d": 999} - low value for "b", high value for "d"
1280        map2_builder.keys().append_value("b");
1281        map2_builder.values().append_value(1);
1282        map2_builder.keys().append_value("d");
1283        map2_builder.values().append_value(999);
1284        map2_builder.append(true).unwrap();
1285
1286        // {"a": 1}
1287        map2_builder.keys().append_value("a");
1288        map2_builder.values().append_value(1);
1289        map2_builder.append(true).unwrap();
1290
1291        // None
1292        map2_builder.append(false).unwrap();
1293
1294        let map2 = map2_builder.finish();
1295
1296        let opts = SortOptions {
1297            descending: false,
1298            nulls_first: true,
1299        };
1300        let cmp = make_comparator(&map1, &map2, opts).unwrap();
1301
1302        // Test that keys have priority over values:
1303        // {"a": 100, "b": 1} vs {"a": 1, "c": 999}
1304        // First entries match (a:100 vs a:1), but 100 > 1, so Greater
1305        assert_eq!(cmp(0, 0), Ordering::Greater);
1306
1307        // {"b": 999, "c": 1} vs {"b": 1, "d": 999}
1308        // First entries match (b:999 vs b:1), but 999 > 1, so Greater
1309        assert_eq!(cmp(1, 1), Ordering::Greater);
1310
1311        // Key comparison: "a" < "b", so {"a": 100, "b": 1} < {"b": 999, "c": 1}
1312        assert_eq!(cmp(0, 1), Ordering::Less);
1313
1314        // Empty map vs non-empty
1315        assert_eq!(cmp(2, 2), Ordering::Less); // {} < {"a": 1}
1316
1317        // Non-null vs null
1318        assert_eq!(cmp(3, 3), Ordering::Greater); // {"x": 1} > None
1319
1320        // Key priority test: "x" > "a", regardless of values
1321        assert_eq!(cmp(3, 0), Ordering::Greater); // {"x": 1} > {"a": 1, "c": 999}
1322
1323        // Empty vs non-empty
1324        assert_eq!(cmp(2, 0), Ordering::Less); // {} < {"a": 1, "c": 999}
1325
1326        let opts = SortOptions {
1327            descending: true,
1328            nulls_first: true,
1329        };
1330        let cmp = make_comparator(&map1, &map2, opts).unwrap();
1331
1332        // With descending=true, value comparison is reversed
1333        assert_eq!(cmp(0, 0), Ordering::Less); // {"a": 100, "b": 1} vs {"a": 1, "c": 999} (reversed)
1334        assert_eq!(cmp(1, 1), Ordering::Less); // {"b": 999, "c": 1} vs {"b": 1, "d": 999} (reversed)
1335        assert_eq!(cmp(0, 1), Ordering::Greater); // {"a": 100, "b": 1} vs {"b": 999, "c": 1} (key order reversed)
1336        assert_eq!(cmp(3, 3), Ordering::Greater); // {"x": 1} > None
1337        assert_eq!(cmp(2, 2), Ordering::Greater); // {} > {"a": 1} (reversed)
1338
1339        let opts = SortOptions {
1340            descending: false,
1341            nulls_first: false,
1342        };
1343        let cmp = make_comparator(&map1, &map2, opts).unwrap();
1344
1345        // Same key priority behavior with nulls_first=false
1346        assert_eq!(cmp(0, 0), Ordering::Greater); // {"a": 100, "b": 1} vs {"a": 1, "c": 999}
1347        assert_eq!(cmp(1, 1), Ordering::Greater); // {"b": 999, "c": 1} vs {"b": 1, "d": 999}
1348        assert_eq!(cmp(3, 3), Ordering::Less); // {"x": 1} < None (nulls last)
1349        assert_eq!(cmp(2, 2), Ordering::Less); // {} < {"a": 1}
1350    }
1351
1352    #[test]
1353    fn test_map_vs_list_consistency() {
1354        // Create map arrays and convert them to list arrays to verify comparison consistency
1355        // Map arrays: [{"a": 1, "b": 2}, {"x": 10}, {}, {"c": 3}]
1356        let string_builder = StringBuilder::new();
1357        let int_builder = Int32Builder::new();
1358        let mut map1_builder = MapBuilder::new(None, string_builder, int_builder);
1359
1360        // {"a": 1, "b": 2}
1361        map1_builder.keys().append_value("a");
1362        map1_builder.values().append_value(1);
1363        map1_builder.keys().append_value("b");
1364        map1_builder.values().append_value(2);
1365        map1_builder.append(true).unwrap();
1366
1367        // {"x": 10}
1368        map1_builder.keys().append_value("x");
1369        map1_builder.values().append_value(10);
1370        map1_builder.append(true).unwrap();
1371
1372        // {}
1373        map1_builder.append(true).unwrap();
1374
1375        // {"c": 3}
1376        map1_builder.keys().append_value("c");
1377        map1_builder.values().append_value(3);
1378        map1_builder.append(true).unwrap();
1379
1380        let map1 = map1_builder.finish();
1381
1382        // Second map array: [{"a": 1, "b": 2}, {"y": 20}, {"d": 4}, None]
1383        let string_builder = StringBuilder::new();
1384        let int_builder = Int32Builder::new();
1385        let mut map2_builder = MapBuilder::new(None, string_builder, int_builder);
1386
1387        // {"a": 1, "b": 2}
1388        map2_builder.keys().append_value("a");
1389        map2_builder.values().append_value(1);
1390        map2_builder.keys().append_value("b");
1391        map2_builder.values().append_value(2);
1392        map2_builder.append(true).unwrap();
1393
1394        // {"y": 20}
1395        map2_builder.keys().append_value("y");
1396        map2_builder.values().append_value(20);
1397        map2_builder.append(true).unwrap();
1398
1399        // {"d": 4}
1400        map2_builder.keys().append_value("d");
1401        map2_builder.values().append_value(4);
1402        map2_builder.append(true).unwrap();
1403
1404        // None
1405        map2_builder.append(false).unwrap();
1406
1407        let map2 = map2_builder.finish();
1408
1409        // Convert map arrays to list arrays (Map entries are struct arrays with key-value pairs)
1410        let list1: ListArray = map1.clone().into();
1411        let list2: ListArray = map2.clone().into();
1412
1413        let test_cases = [
1414            SortOptions {
1415                descending: false,
1416                nulls_first: true,
1417            },
1418            SortOptions {
1419                descending: true,
1420                nulls_first: true,
1421            },
1422            SortOptions {
1423                descending: false,
1424                nulls_first: false,
1425            },
1426            SortOptions {
1427                descending: true,
1428                nulls_first: false,
1429            },
1430        ];
1431
1432        for opts in test_cases {
1433            let map_cmp = make_comparator(&map1, &map2, opts).unwrap();
1434            let list_cmp = make_comparator(&list1, &list2, opts).unwrap();
1435
1436            // Test all possible index combinations
1437            for i in 0..map1.len() {
1438                for j in 0..map2.len() {
1439                    let map_result = map_cmp(i, j);
1440                    let list_result = list_cmp(i, j);
1441                    assert_eq!(
1442                        map_result, list_result,
1443                        "Map comparison and List comparison should be equal for indices ({i}, {j}) with opts {opts:?}. Map: {map_result:?}, List: {list_result:?}"
1444                    );
1445                }
1446            }
1447        }
1448    }
1449
1450    #[test]
1451    fn test_dense_union() {
1452        // create a dense union array with Int32 (type_id = 0) and Utf8 (type_id=1)
1453        // the values are: [1, "b", 2, "a", 3]
1454        //  type_ids are: [0,  1,  0,  1,  0]
1455        //   offsets are: [0, 0, 1, 1, 2] from [1, 2, 3] and ["b", "a"]
1456        let int_array = Int32Array::from(vec![1, 2, 3]);
1457        let str_array = StringArray::from(vec!["b", "a"]);
1458
1459        let type_ids = [0, 1, 0, 1, 0].into_iter().collect::<ScalarBuffer<i8>>();
1460        let offsets = [0, 0, 1, 1, 2].into_iter().collect::<ScalarBuffer<i32>>();
1461
1462        let union_fields = [
1463            (0, Arc::new(Field::new("A", DataType::Int32, false))),
1464            (1, Arc::new(Field::new("B", DataType::Utf8, false))),
1465        ]
1466        .into_iter()
1467        .collect::<UnionFields>();
1468
1469        let children = vec![Arc::new(int_array) as ArrayRef, Arc::new(str_array)];
1470
1471        let array1 =
1472            UnionArray::try_new(union_fields.clone(), type_ids, Some(offsets), children).unwrap();
1473
1474        // create a second array: [2, "a", 1, "c"]
1475        //          type ids are: [0,  1,  0,  1]
1476        //           offsets are: [0, 0, 1, 1] from [2, 1] and ["a", "c"]
1477        let int_array2 = Int32Array::from(vec![2, 1]);
1478        let str_array2 = StringArray::from(vec!["a", "c"]);
1479        let type_ids2 = [0, 1, 0, 1].into_iter().collect::<ScalarBuffer<i8>>();
1480        let offsets2 = [0, 0, 1, 1].into_iter().collect::<ScalarBuffer<i32>>();
1481
1482        let children2 = vec![Arc::new(int_array2) as ArrayRef, Arc::new(str_array2)];
1483
1484        let array2 =
1485            UnionArray::try_new(union_fields, type_ids2, Some(offsets2), children2).unwrap();
1486
1487        let opts = SortOptions {
1488            descending: false,
1489            nulls_first: true,
1490        };
1491
1492        // comparing
1493        // [1, "b", 2, "a", 3]
1494        // [2, "a", 1, "c"]
1495        let cmp = make_comparator(&array1, &array2, opts).unwrap();
1496
1497        // array1[0] = (type_id=0, value=1)
1498        // array2[0] = (type_id=0, value=2)
1499        assert_eq!(cmp(0, 0), Ordering::Less); // 1 < 2
1500
1501        // array1[0] = (type_id=0, value=1)
1502        // array2[1] = (type_id=1, value="a")
1503        assert_eq!(cmp(0, 1), Ordering::Less); // type_id 0 < 1
1504
1505        // array1[1] = (type_id=1, value="b")
1506        // array2[1] = (type_id=1, value="a")
1507        assert_eq!(cmp(1, 1), Ordering::Greater); // "b" > "a"
1508
1509        // array1[2] = (type_id=0, value=2)
1510        // array2[0] = (type_id=0, value=2)
1511        assert_eq!(cmp(2, 0), Ordering::Equal); // 2 == 2
1512
1513        // array1[3] = (type_id=1, value="a")
1514        // array2[1] = (type_id=1, value="a")
1515        assert_eq!(cmp(3, 1), Ordering::Equal); // "a" == "a"
1516
1517        // array1[1] = (type_id=1, value="b")
1518        // array2[3] = (type_id=1, value="c")
1519        assert_eq!(cmp(1, 3), Ordering::Less); // "b" < "c"
1520
1521        let opts_desc = SortOptions {
1522            descending: true,
1523            nulls_first: true,
1524        };
1525        let cmp_desc = make_comparator(&array1, &array2, opts_desc).unwrap();
1526
1527        assert_eq!(cmp_desc(0, 0), Ordering::Greater); // 1 > 2 (reversed)
1528        assert_eq!(cmp_desc(0, 1), Ordering::Greater); // type_id 0 < 1, reversed to Greater
1529        assert_eq!(cmp_desc(1, 1), Ordering::Less); // "b" < "a" (reversed)
1530    }
1531
1532    #[test]
1533    fn test_sparse_union() {
1534        // create a sparse union array with Int32 (type_id=0) and Utf8 (type_id=1)
1535        // values: [1, "b", 3]
1536        // note, in sparse unions, child arrays have the same length as the union
1537        let int_array = Int32Array::from(vec![Some(1), None, Some(3)]);
1538        let str_array = StringArray::from(vec![None, Some("b"), None]);
1539        let type_ids = [0, 1, 0].into_iter().collect::<ScalarBuffer<i8>>();
1540
1541        let union_fields = [
1542            (0, Arc::new(Field::new("a", DataType::Int32, false))),
1543            (1, Arc::new(Field::new("b", DataType::Utf8, false))),
1544        ]
1545        .into_iter()
1546        .collect::<UnionFields>();
1547
1548        let children = vec![Arc::new(int_array) as ArrayRef, Arc::new(str_array)];
1549
1550        let array = UnionArray::try_new(union_fields, type_ids, None, children).unwrap();
1551
1552        let opts = SortOptions::default();
1553        let cmp = make_comparator(&array, &array, opts).unwrap();
1554
1555        // array[0] = (type_id=0, value=1), array[2] = (type_id=0, value=3)
1556        assert_eq!(cmp(0, 2), Ordering::Less); // 1 < 3
1557        // array[0] = (type_id=0, value=1), array[1] = (type_id=1, value="b")
1558        assert_eq!(cmp(0, 1), Ordering::Less); // type_id 0 < 1
1559    }
1560
1561    #[test]
1562    #[should_panic(expected = "index out of bounds")]
1563    fn test_union_out_of_bounds() {
1564        // create a dense union array with 3 elements
1565        let int_array = Int32Array::from(vec![1, 2]);
1566        let str_array = StringArray::from(vec!["a"]);
1567
1568        let type_ids = [0, 1, 0].into_iter().collect::<ScalarBuffer<i8>>();
1569        let offsets = [0, 0, 1].into_iter().collect::<ScalarBuffer<i32>>();
1570
1571        let union_fields = [
1572            (0, Arc::new(Field::new("A", DataType::Int32, false))),
1573            (1, Arc::new(Field::new("B", DataType::Utf8, false))),
1574        ]
1575        .into_iter()
1576        .collect::<UnionFields>();
1577
1578        let children = vec![Arc::new(int_array) as ArrayRef, Arc::new(str_array)];
1579
1580        let array = UnionArray::try_new(union_fields, type_ids, Some(offsets), children).unwrap();
1581
1582        let opts = SortOptions::default();
1583        let cmp = make_comparator(&array, &array, opts).unwrap();
1584
1585        // oob
1586        cmp(0, 3);
1587    }
1588
1589    #[test]
1590    fn test_union_incompatible_fields() {
1591        // create first union with Int32 and Utf8
1592        let int_array1 = Int32Array::from(vec![1, 2]);
1593        let str_array1 = StringArray::from(vec!["a", "b"]);
1594
1595        let type_ids1 = [0, 1].into_iter().collect::<ScalarBuffer<i8>>();
1596        let offsets1 = [0, 0].into_iter().collect::<ScalarBuffer<i32>>();
1597
1598        let union_fields1 = [
1599            (0, Arc::new(Field::new("A", DataType::Int32, false))),
1600            (1, Arc::new(Field::new("B", DataType::Utf8, false))),
1601        ]
1602        .into_iter()
1603        .collect::<UnionFields>();
1604
1605        let children1 = vec![Arc::new(int_array1) as ArrayRef, Arc::new(str_array1)];
1606
1607        let array1 =
1608            UnionArray::try_new(union_fields1, type_ids1, Some(offsets1), children1).unwrap();
1609
1610        // create second union with Int32 and Float64 (incompatible with first)
1611        let int_array2 = Int32Array::from(vec![3, 4]);
1612        let float_array2 = Float64Array::from(vec![1.0, 2.0]);
1613
1614        let type_ids2 = [0, 1].into_iter().collect::<ScalarBuffer<i8>>();
1615        let offsets2 = [0, 0].into_iter().collect::<ScalarBuffer<i32>>();
1616
1617        let union_fields2 = [
1618            (0, Arc::new(Field::new("A", DataType::Int32, false))),
1619            (1, Arc::new(Field::new("C", DataType::Float64, false))),
1620        ]
1621        .into_iter()
1622        .collect::<UnionFields>();
1623
1624        let children2 = vec![Arc::new(int_array2) as ArrayRef, Arc::new(float_array2)];
1625
1626        let array2 =
1627            UnionArray::try_new(union_fields2, type_ids2, Some(offsets2), children2).unwrap();
1628
1629        let opts = SortOptions::default();
1630
1631        let Result::Err(ArrowError::InvalidArgumentError(out)) =
1632            make_comparator(&array1, &array2, opts)
1633        else {
1634            panic!("expected error when making comparator of incompatible union arrays");
1635        };
1636
1637        assert_eq!(
1638            &out,
1639            "Cannot compare UnionArrays with different fields: left=[(0, Field { name: \"A\", data_type: Int32 }), (1, Field { name: \"B\", data_type: Utf8 })], right=[(0, Field { name: \"A\", data_type: Int32 }), (1, Field { name: \"C\", data_type: Float64 })]"
1640        );
1641    }
1642
1643    #[test]
1644    fn test_union_incompatible_modes() {
1645        // create first union as Dense with Int32 and Utf8
1646        let int_array1 = Int32Array::from(vec![1, 2]);
1647        let str_array1 = StringArray::from(vec!["a", "b"]);
1648
1649        let type_ids1 = [0, 1].into_iter().collect::<ScalarBuffer<i8>>();
1650        let offsets1 = [0, 0].into_iter().collect::<ScalarBuffer<i32>>();
1651
1652        let union_fields1 = [
1653            (0, Arc::new(Field::new("A", DataType::Int32, false))),
1654            (1, Arc::new(Field::new("B", DataType::Utf8, false))),
1655        ]
1656        .into_iter()
1657        .collect::<UnionFields>();
1658
1659        let children1 = vec![Arc::new(int_array1) as ArrayRef, Arc::new(str_array1)];
1660
1661        let array1 =
1662            UnionArray::try_new(union_fields1.clone(), type_ids1, Some(offsets1), children1)
1663                .unwrap();
1664
1665        // create second union as Sparse with same fields (Int32 and Utf8)
1666        let int_array2 = Int32Array::from(vec![Some(3), None]);
1667        let str_array2 = StringArray::from(vec![None, Some("c")]);
1668
1669        let type_ids2 = [0, 1].into_iter().collect::<ScalarBuffer<i8>>();
1670
1671        let children2 = vec![Arc::new(int_array2) as ArrayRef, Arc::new(str_array2)];
1672
1673        let array2 = UnionArray::try_new(union_fields1, type_ids2, None, children2).unwrap();
1674
1675        let opts = SortOptions::default();
1676
1677        let Result::Err(ArrowError::InvalidArgumentError(out)) =
1678            make_comparator(&array1, &array2, opts)
1679        else {
1680            panic!("expected error when making comparator of union arrays with different modes");
1681        };
1682
1683        assert_eq!(
1684            &out,
1685            "Cannot compare UnionArrays with different modes: left=Dense, right=Sparse"
1686        );
1687    }
1688
1689    #[test]
1690    fn test_null_array_cmp() {
1691        let a = NullArray::new(3);
1692        let b = NullArray::new(3);
1693        let cmp = make_comparator(&a, &b, SortOptions::default()).unwrap();
1694
1695        assert_eq!(cmp(0, 0), Ordering::Equal);
1696        assert_eq!(cmp(0, 1), Ordering::Equal);
1697        assert_eq!(cmp(2, 0), Ordering::Equal);
1698    }
1699
1700    #[test]
1701    fn test_run_end_encoded_int32() {
1702        // Create RunEndEncoded arrays:
1703        // array1: [1, 1, 2, 2, 2, 3]
1704        // run_ends1: [2, 5, 6], values1: [1, 2, 3]
1705        let run_ends1 = Int32Array::from(vec![2, 5, 6]);
1706        let values1 = Int32Array::from(vec![1, 2, 3]);
1707        let array1 = RunArray::<Int32Type>::try_new(&run_ends1, &values1).unwrap();
1708
1709        // array2: [1, 2, 2, 3, 3, 3]
1710        // run_ends2: [1, 3, 6], values2: [1, 2, 3]
1711        let run_ends2 = Int32Array::from(vec![1, 3, 6]);
1712        let values2 = Int32Array::from(vec![1, 2, 3]);
1713        let array2 = RunArray::<Int32Type>::try_new(&run_ends2, &values2).unwrap();
1714
1715        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
1716
1717        // array1[0] = 1, array2[0] = 1
1718        assert_eq!(cmp(0, 0), Ordering::Equal);
1719        // array1[0] = 1, array2[1] = 2
1720        assert_eq!(cmp(0, 1), Ordering::Less);
1721        // array1[2] = 2, array2[1] = 2
1722        assert_eq!(cmp(2, 1), Ordering::Equal);
1723        // array1[5] = 3, array2[5] = 3
1724        assert_eq!(cmp(5, 5), Ordering::Equal);
1725        // array1[1] = 1, array2[2] = 2
1726        assert_eq!(cmp(1, 2), Ordering::Less);
1727        // array1[4] = 2, array2[4] = 3
1728        assert_eq!(cmp(4, 4), Ordering::Less);
1729    }
1730
1731    #[test]
1732    fn test_run_end_encoded_with_nulls() {
1733        // Create RunEndEncoded arrays with nulls:
1734        // array1: [1, 1, null, null, 2]
1735        // run_ends1: [2, 4, 5], values1: [1, null, 2]
1736        let run_ends1 = Int32Array::from(vec![2, 4, 5]);
1737        let values1 = Int32Array::from(vec![Some(1), None, Some(2)]);
1738        let array1 = RunArray::<Int32Type>::try_new(&run_ends1, &values1).unwrap();
1739
1740        // array2: [null, 1, 1, 2, null]
1741        // run_ends2: [1, 3, 4, 5], values2: [null, 1, 2, null]
1742        let run_ends2 = Int32Array::from(vec![1, 3, 4, 5]);
1743        let values2 = Int32Array::from(vec![None, Some(1), Some(2), None]);
1744        let array2 = RunArray::<Int32Type>::try_new(&run_ends2, &values2).unwrap();
1745
1746        let opts = SortOptions::default();
1747        let cmp = make_comparator(&array1, &array2, opts).unwrap();
1748
1749        // array1[0] = 1, array2[1] = 1
1750        assert_eq!(cmp(0, 1), Ordering::Equal);
1751        // array1[2] = null, array2[0] = null
1752        assert_eq!(cmp(2, 0), Ordering::Equal);
1753        // array1[0] = 1, array2[0] = null (nulls first by default)
1754        assert_eq!(cmp(0, 0), Ordering::Greater);
1755        // array1[2] = null, array2[1] = 1
1756        assert_eq!(cmp(2, 1), Ordering::Less);
1757    }
1758
1759    #[test]
1760    fn test_run_end_encoded_int16() {
1761        // Test with Int16 run ends
1762        let run_ends1 = Int16Array::from(vec![3_i16, 5, 6]);
1763        let values1 = StringArray::from(vec!["a", "b", "c"]);
1764        let array1 = RunArray::<Int16Type>::try_new(&run_ends1, &values1).unwrap();
1765
1766        let run_ends2 = Int16Array::from(vec![2_i16, 4, 6]);
1767        let values2 = StringArray::from(vec!["a", "b", "c"]);
1768        let array2 = RunArray::<Int16Type>::try_new(&run_ends2, &values2).unwrap();
1769
1770        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
1771
1772        // array1: [a, a, a, b, b, c]
1773        // array2: [a, a, b, b, c, c]
1774        assert_eq!(cmp(0, 0), Ordering::Equal); // a vs a
1775        assert_eq!(cmp(2, 2), Ordering::Less); // a vs b
1776        assert_eq!(cmp(3, 2), Ordering::Equal); // b vs b
1777        assert_eq!(cmp(5, 4), Ordering::Equal); // c vs c
1778    }
1779
1780    #[test]
1781    fn test_run_end_encoded_int64() {
1782        // Test with Int64 run ends
1783        let run_ends1 = Int64Array::from(vec![2_i64, 4, 6]);
1784        let values1 = Int64Array::from(vec![10_i64, 20, 30]);
1785        let array1 = RunArray::<Int64Type>::try_new(&run_ends1, &values1).unwrap();
1786
1787        let run_ends2 = Int64Array::from(vec![3_i64, 5, 6]);
1788        let values2 = Int64Array::from(vec![10_i64, 20, 30]);
1789        let array2 = RunArray::<Int64Type>::try_new(&run_ends2, &values2).unwrap();
1790
1791        let cmp = make_comparator(&array1, &array2, SortOptions::default()).unwrap();
1792
1793        // array1: [10, 10, 20, 20, 30, 30]
1794        // array2: [10, 10, 10, 20, 20, 30]
1795        assert_eq!(cmp(0, 0), Ordering::Equal); // 10 vs 10
1796        assert_eq!(cmp(1, 2), Ordering::Equal); // 10 vs 10
1797        assert_eq!(cmp(2, 3), Ordering::Equal); // 20 vs 20
1798        assert_eq!(cmp(4, 4), Ordering::Greater); // 30 vs 20
1799    }
1800
1801    #[test]
1802    fn test_run_end_encoded_sliced() {
1803        // Create a RunEndEncoded array and slice it:
1804        // original: [1, 1, 2, 2, 2, 3, 3, 4]
1805        // run_ends: [2, 5, 7, 8], values: [1, 2, 3, 4]
1806        let run_ends = Int32Array::from(vec![2, 5, 7, 8]);
1807        let values = Int32Array::from(vec![1, 2, 3, 4]);
1808        let array = RunArray::<Int32Type>::try_new(&run_ends, &values).unwrap();
1809
1810        // slice1 = array[1..5] => [1, 2, 2, 2]
1811        let slice1 = array.slice(1, 4);
1812        // slice2 = array[3..7] => [2, 2, 3, 3]
1813        let slice2 = array.slice(3, 4);
1814
1815        let cmp = make_comparator(&slice1, &slice2, SortOptions::default()).unwrap();
1816
1817        // slice1[0]=1, slice2[0]=2
1818        assert_eq!(cmp(0, 0), Ordering::Less);
1819        // slice1[1]=2, slice2[0]=2
1820        assert_eq!(cmp(1, 0), Ordering::Equal);
1821        // slice1[3]=2, slice2[2]=3
1822        assert_eq!(cmp(3, 2), Ordering::Less);
1823        // slice1[1]=2, slice2[3]=3
1824        assert_eq!(cmp(1, 3), Ordering::Less);
1825
1826        // Compare a sliced array with an unsliced array
1827        let run_ends2 = Int32Array::from(vec![2, 4]);
1828        let values2 = Int32Array::from(vec![1, 2]);
1829        let array2 = RunArray::<Int32Type>::try_new(&run_ends2, &values2).unwrap();
1830
1831        let cmp = make_comparator(&slice1, &array2, SortOptions::default()).unwrap();
1832
1833        // slice1[0]=1, array2[0]=1
1834        assert_eq!(cmp(0, 0), Ordering::Equal);
1835        // slice1[1]=2, array2[1]=1
1836        assert_eq!(cmp(1, 1), Ordering::Greater);
1837        // slice1[3]=2, array2[3]=2
1838        assert_eq!(cmp(3, 3), Ordering::Equal);
1839    }
1840
1841    #[test]
1842    fn test_run_end_encoded_sliced_with_nulls() {
1843        // Create a RunEndEncoded array with nulls:
1844        // original: [1, 1, null, null, 2, 2, null, 3]
1845        // run_ends: [2, 4, 6, 7, 8], values: [1, null, 2, null, 3]
1846        let run_ends = Int32Array::from(vec![2, 4, 6, 7, 8]);
1847        let values = Int32Array::from(vec![Some(1), None, Some(2), None, Some(3)]);
1848        let array = RunArray::<Int32Type>::try_new(&run_ends, &values).unwrap();
1849
1850        // slice1 = array[1..6] => [1, null, null, 2, 2]
1851        let slice1 = array.slice(1, 5);
1852        // slice2 = array[3..8] => [null, 2, 2, null, 3]
1853        let slice2 = array.slice(3, 5);
1854
1855        let opts = SortOptions::default(); // nulls_first=true, descending=false
1856        let cmp = make_comparator(&slice1, &slice2, opts).unwrap();
1857
1858        // slice1[0]=1, slice2[0]=null
1859        assert_eq!(cmp(0, 0), Ordering::Greater);
1860        // slice1[1]=null, slice2[0]=null
1861        assert_eq!(cmp(1, 0), Ordering::Equal);
1862        // slice1[1]=null, slice2[1]=2
1863        assert_eq!(cmp(1, 1), Ordering::Less);
1864        // slice1[3]=2, slice2[1]=2
1865        assert_eq!(cmp(3, 1), Ordering::Equal);
1866        // slice1[4]=2, slice2[4]=3
1867        assert_eq!(cmp(4, 4), Ordering::Less);
1868        // slice1[3]=2, slice2[3]=null
1869        assert_eq!(cmp(3, 3), Ordering::Greater);
1870    }
1871
1872    #[test]
1873    fn test_run_end_encoded_different_types() {
1874        // Test with different run end types - should fail
1875        let run_ends1 = Int32Array::from(vec![2, 4, 6]);
1876        let values1 = Int32Array::from(vec![1, 2, 3]);
1877        let array1 = RunArray::<Int32Type>::try_new(&run_ends1, &values1).unwrap();
1878
1879        let run_ends2 = Int64Array::from(vec![2_i64, 4, 6]);
1880        let values2 = Int64Array::from(vec![1_i64, 2, 3]);
1881        let array2 = RunArray::<Int64Type>::try_new(&run_ends2, &values2).unwrap();
1882
1883        let result = make_comparator(&array1, &array2, SortOptions::default());
1884        assert!(result.is_err());
1885        let err = match result {
1886            Err(e) => e.to_string(),
1887            Ok(_) => panic!("Expected error"),
1888        };
1889        assert!(err.contains("Cannot compare RunEndEncoded arrays"));
1890    }
1891}