1use crate::{RowConverter, Rows, SortField, variable};
19use arrow_array::types::RunEndIndexType;
20use arrow_array::{PrimitiveArray, RunArray};
21use arrow_buffer::{ArrowNativeType, ScalarBuffer};
22use arrow_schema::{ArrowError, SortOptions};
23
24pub fn compute_lengths<R: RunEndIndexType>(
26 lengths: &mut [usize],
27 rows: &Rows,
28 array: &RunArray<R>,
29) {
30 let run_ends = array.run_ends().sliced_values();
31 let mut logical_start = 0;
32
33 for (physical_idx, run_end) in run_ends.enumerate() {
35 let logical_end = run_end.as_usize();
36 let row_len = rows.row_len(physical_idx);
37 let encoded_len = variable::padded_length(Some(row_len));
38
39 for length in &mut lengths[logical_start..logical_end] {
41 *length += encoded_len;
42 }
43
44 logical_start = logical_end;
45 }
46}
47
48pub fn encode<R: RunEndIndexType>(
52 data: &mut [u8],
53 offsets: &mut [usize],
54 rows: &Rows,
55 opts: SortOptions,
56 array: &RunArray<R>,
57) {
58 let run_ends = array.run_ends().sliced_values();
59 let mut logical_idx = 0;
60 let mut offset_idx = 1; for (physical_idx, run_end) in run_ends.enumerate() {
64 let run_end = run_end.as_usize();
65 let iteration_count = run_end - logical_idx;
66
67 let first_offset = offsets[offset_idx];
68 let out = &mut data[first_offset..];
69 let bytes_written = variable::encode_one(out, Some(rows.row(physical_idx).data), opts);
70 offsets[offset_idx] += bytes_written;
71 for i in 1..iteration_count {
73 let dst = offsets[offset_idx + i];
74 data.copy_within(first_offset..first_offset + bytes_written, dst);
75 offsets[offset_idx + i] += bytes_written;
76 }
77 logical_idx = run_end;
78 offset_idx += iteration_count;
79 }
80}
81
82pub unsafe fn decode<R: RunEndIndexType>(
88 converter: &RowConverter,
89 rows: &mut [&[u8]],
90 field: &SortField,
91 validate_utf8: bool,
92) -> Result<RunArray<R>, ArrowError> {
93 if rows.is_empty() {
94 let values = unsafe { converter.convert_raw(&mut [], validate_utf8) }?;
95 let run_ends_array = PrimitiveArray::<R>::try_new(ScalarBuffer::from(vec![]), None)?;
96 return RunArray::<R>::try_new(&run_ends_array, &values[0]);
97 }
98
99 let mut decoded_values = Vec::new();
101 let mut run_ends = Vec::new();
102 let mut unique_row_indices = Vec::new();
103
104 let mut decoded_data = Vec::new();
106 for (idx, row) in rows.iter_mut().enumerate() {
107 decoded_data.clear();
108 let consumed = variable::decode_blocks(row, field.options, |block| {
110 decoded_data.extend_from_slice(block);
111 });
112
113 if field.options.descending {
115 decoded_data.iter_mut().for_each(|b| *b = !*b);
116 }
117
118 *row = &row[consumed..];
120
121 let is_new_run =
123 idx == 0 || decoded_data != decoded_values[*unique_row_indices.last().unwrap()];
124
125 if is_new_run {
126 if idx > 0 {
128 run_ends.push(R::Native::usize_as(idx));
129 }
130 unique_row_indices.push(decoded_values.len());
131 let capacity = decoded_data.capacity();
132 decoded_values.push(std::mem::replace(
133 &mut decoded_data,
134 Vec::with_capacity(capacity),
135 ));
136 }
137 }
138 run_ends.push(R::Native::usize_as(rows.len()));
140
141 let mut unique_rows: Vec<&[u8]> = decoded_values.iter().map(|v| v.as_slice()).collect();
143 let values = if unique_rows.is_empty() {
144 unsafe { converter.convert_raw(&mut [], validate_utf8) }?
145 } else {
146 unsafe { converter.convert_raw(&mut unique_rows, validate_utf8) }?
147 };
148
149 let run_ends_array = PrimitiveArray::<R>::try_new(ScalarBuffer::from(run_ends), None)?;
151
152 RunArray::<R>::try_new(&run_ends_array, &values[0])
154}
155
156#[cfg(test)]
157mod tests {
158 use crate::{RowConverter, SortField};
159 use arrow_array::cast::AsArray;
160 use arrow_array::types::{Int16Type, Int32Type, Int64Type, RunEndIndexType};
161 use arrow_array::{Array, Int64Array, PrimitiveArray, RunArray, StringArray};
162 use arrow_schema::{DataType, Field, SortOptions};
163 use std::sync::Arc;
164
165 fn assert_roundtrip<R: RunEndIndexType>(
166 array: &RunArray<R>,
167 run_end_type: DataType,
168 values_type: DataType,
169 sort_options: Option<SortOptions>,
170 ) {
171 let sort_field = if let Some(options) = sort_options {
172 SortField::new_with_options(
173 DataType::RunEndEncoded(
174 Arc::new(Field::new(
175 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
176 run_end_type,
177 false,
178 )),
179 Arc::new(Field::new(
180 Field::REE_VALUES_FIELD_DEFAULT_NAME,
181 values_type,
182 true,
183 )),
184 ),
185 options,
186 )
187 } else {
188 SortField::new(DataType::RunEndEncoded(
189 Arc::new(Field::new(
190 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
191 run_end_type,
192 false,
193 )),
194 Arc::new(Field::new(
195 Field::REE_VALUES_FIELD_DEFAULT_NAME,
196 values_type,
197 true,
198 )),
199 ))
200 };
201
202 let converter = RowConverter::new(vec![sort_field]).unwrap();
203
204 let rows = converter
205 .convert_columns(&[Arc::new(array.clone())])
206 .unwrap();
207
208 let arrays = converter.convert_rows(&rows).unwrap();
209 let result = arrays[0].as_any().downcast_ref::<RunArray<R>>().unwrap();
210
211 assert_eq!(array, result);
212 }
213
214 #[test]
215 fn test_run_end_encoded_supports_datatype() {
216 assert!(RowConverter::supports_datatype(&DataType::RunEndEncoded(
218 Arc::new(Field::new(
219 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
220 DataType::Int32,
221 false
222 )),
223 Arc::new(Field::new(
224 Field::REE_VALUES_FIELD_DEFAULT_NAME,
225 DataType::Utf8,
226 true
227 )),
228 )));
229 }
230
231 #[test]
232 fn test_run_end_encoded_round_trip_int16_int64s() {
233 let values = Int64Array::from(vec![100, 200, 100, 300]);
237 let run_ends = vec![2, 3, 5, 6];
238 let array: RunArray<Int16Type> =
239 RunArray::try_new(&PrimitiveArray::from(run_ends), &values).unwrap();
240
241 assert_roundtrip(&array, DataType::Int16, DataType::Int64, None);
242 }
243
244 #[test]
245 fn test_run_end_encoded_round_trip_int32_int64s() {
246 let values = Int64Array::from(vec![100, 200, 100, 300]);
250 let run_ends = vec![2, 3, 5, 6];
251 let array: RunArray<Int32Type> =
252 RunArray::try_new(&PrimitiveArray::from(run_ends), &values).unwrap();
253
254 assert_roundtrip(&array, DataType::Int32, DataType::Int64, None);
255 }
256
257 #[test]
258 fn test_run_end_encoded_round_trip_int64_int64s() {
259 let values = Int64Array::from(vec![100, 200, 100, 300]);
263 let run_ends = vec![2, 3, 5, 6];
264 let array: RunArray<Int64Type> =
265 RunArray::try_new(&PrimitiveArray::from(run_ends), &values).unwrap();
266
267 assert_roundtrip(&array, DataType::Int64, DataType::Int64, None);
268 }
269
270 #[test]
271 fn test_run_end_encoded_round_trip_strings() {
272 let array: RunArray<Int32Type> = vec!["b", "b", "a"].into_iter().collect();
275
276 assert_roundtrip(&array, DataType::Int32, DataType::Utf8, None);
277 }
278
279 #[test]
280 fn test_run_end_encoded_round_trip_strings_with_nulls() {
281 let array: RunArray<Int32Type> = vec![Some("b"), Some("b"), None, Some("a")]
284 .into_iter()
285 .collect();
286
287 assert_roundtrip(&array, DataType::Int32, DataType::Utf8, None);
288 }
289
290 #[test]
291 fn test_run_end_encoded_ascending_descending_round_trip() {
292 let values_asc =
295 arrow_array::StringArray::from(vec![Some("apple"), Some("banana"), Some("cherry")]);
296 let run_ends_asc = vec![2, 4, 6];
297 let run_array_asc: RunArray<Int32Type> = RunArray::try_new(
298 &arrow_array::PrimitiveArray::from(run_ends_asc),
299 &values_asc,
300 )
301 .unwrap();
302
303 assert_roundtrip(
305 &run_array_asc,
306 DataType::Int32,
307 DataType::Utf8,
308 Some(SortOptions {
309 descending: false,
310 nulls_first: true,
311 }),
312 );
313
314 assert_roundtrip(
316 &run_array_asc,
317 DataType::Int32,
318 DataType::Utf8,
319 Some(SortOptions {
320 descending: true,
321 nulls_first: true,
322 }),
323 );
324 }
325
326 #[test]
327 fn test_run_end_encoded_sort_configurations_basic() {
328 let test_array: RunArray<Int32Type> = vec!["test"].into_iter().collect();
331
332 assert_roundtrip(
334 &test_array,
335 DataType::Int32,
336 DataType::Utf8,
337 Some(SortOptions {
338 descending: false,
339 nulls_first: true,
340 }),
341 );
342
343 assert_roundtrip(
345 &test_array,
346 DataType::Int32,
347 DataType::Utf8,
348 Some(SortOptions {
349 descending: true,
350 nulls_first: true,
351 }),
352 );
353 }
354
355 #[test]
356 fn test_run_end_encoded_nulls_first_last_configurations() {
357 let simple_array: RunArray<Int32Type> = vec!["simple"].into_iter().collect();
360
361 let converter_nulls_first = RowConverter::new(vec![SortField::new_with_options(
362 DataType::RunEndEncoded(
363 Arc::new(Field::new(
364 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
365 DataType::Int32,
366 false,
367 )),
368 Arc::new(Field::new(
369 Field::REE_VALUES_FIELD_DEFAULT_NAME,
370 DataType::Utf8,
371 true,
372 )),
373 ),
374 SortOptions {
375 descending: false,
376 nulls_first: true,
377 },
378 )])
379 .unwrap();
380
381 let converter_nulls_last = RowConverter::new(vec![SortField::new_with_options(
382 DataType::RunEndEncoded(
383 Arc::new(Field::new(
384 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
385 DataType::Int32,
386 false,
387 )),
388 Arc::new(Field::new(
389 Field::REE_VALUES_FIELD_DEFAULT_NAME,
390 DataType::Utf8,
391 true,
392 )),
393 ),
394 SortOptions {
395 descending: false,
396 nulls_first: false,
397 },
398 )])
399 .unwrap();
400
401 let rows_nulls_first = converter_nulls_first
403 .convert_columns(&[Arc::new(simple_array.clone())])
404 .unwrap();
405 let arrays_nulls_first = converter_nulls_first
406 .convert_rows(&rows_nulls_first)
407 .unwrap();
408 let result_nulls_first = arrays_nulls_first[0]
409 .as_any()
410 .downcast_ref::<RunArray<Int32Type>>()
411 .unwrap();
412
413 let rows_nulls_last = converter_nulls_last
414 .convert_columns(&[Arc::new(simple_array.clone())])
415 .unwrap();
416 let arrays_nulls_last = converter_nulls_last.convert_rows(&rows_nulls_last).unwrap();
417 let result_nulls_last = arrays_nulls_last[0]
418 .as_any()
419 .downcast_ref::<RunArray<Int32Type>>()
420 .unwrap();
421
422 assert_eq!(simple_array.len(), result_nulls_first.len());
424 assert_eq!(simple_array.len(), result_nulls_last.len());
425 }
426
427 #[test]
428 fn test_run_end_encoded_row_consumption() {
429 let array: RunArray<Int32Type> = vec!["a", "a", "b", "b", "b", "c"].into_iter().collect();
435 let string_array = StringArray::from(vec!["x", "y", "z", "w", "u", "v"]);
436
437 let multi_converter = RowConverter::new(vec![
438 SortField::new(DataType::RunEndEncoded(
439 Arc::new(Field::new(
440 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
441 DataType::Int32,
442 false,
443 )),
444 Arc::new(Field::new(
445 Field::REE_VALUES_FIELD_DEFAULT_NAME,
446 DataType::Utf8,
447 true,
448 )),
449 )),
450 SortField::new(DataType::Utf8),
451 ])
452 .unwrap();
453
454 let multi_rows = multi_converter
455 .convert_columns(&[Arc::new(array.clone()), Arc::new(string_array.clone())])
456 .unwrap();
457
458 let arrays = multi_converter.convert_rows(&multi_rows).unwrap();
460
461 let result_ree = arrays[0]
463 .as_any()
464 .downcast_ref::<RunArray<Int32Type>>()
465 .unwrap();
466
467 let result_string = arrays[1].as_any().downcast_ref::<StringArray>().unwrap();
468
469 assert_eq!(result_ree.values().as_ref(), array.values().as_ref());
471 assert_eq!(result_ree.run_ends().values(), array.run_ends().values());
472 assert_eq!(*result_string, string_array);
473 }
474
475 #[test]
476 fn test_run_end_encoded_sorting_behavior() {
477 let array1: RunArray<Int32Type> = vec!["apple", "apple"].into_iter().collect();
481 let array2: RunArray<Int32Type> = vec!["banana", "banana"].into_iter().collect();
482 let array3: RunArray<Int32Type> = vec!["cherry", "cherry"].into_iter().collect();
483
484 let converter_asc = RowConverter::new(vec![SortField::new(DataType::RunEndEncoded(
486 Arc::new(Field::new(
487 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
488 DataType::Int32,
489 false,
490 )),
491 Arc::new(Field::new(
492 Field::REE_VALUES_FIELD_DEFAULT_NAME,
493 DataType::Utf8,
494 true,
495 )),
496 ))])
497 .unwrap();
498
499 let rows1_asc = converter_asc
500 .convert_columns(&[Arc::new(array1.clone())])
501 .unwrap();
502 let rows2_asc = converter_asc
503 .convert_columns(&[Arc::new(array2.clone())])
504 .unwrap();
505 let rows3_asc = converter_asc
506 .convert_columns(&[Arc::new(array3.clone())])
507 .unwrap();
508
509 assert!(
512 rows1_asc.row(0) < rows2_asc.row(0),
513 "apple should come before banana in ascending order"
514 );
515 assert!(
516 rows2_asc.row(0) < rows3_asc.row(0),
517 "banana should come before cherry in ascending order"
518 );
519 assert!(
520 rows1_asc.row(0) < rows3_asc.row(0),
521 "apple should come before cherry in ascending order"
522 );
523
524 let converter_desc = RowConverter::new(vec![SortField::new_with_options(
526 DataType::RunEndEncoded(
527 Arc::new(Field::new(
528 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
529 DataType::Int32,
530 false,
531 )),
532 Arc::new(Field::new(
533 Field::REE_VALUES_FIELD_DEFAULT_NAME,
534 DataType::Utf8,
535 true,
536 )),
537 ),
538 arrow_schema::SortOptions {
539 descending: true,
540 nulls_first: true,
541 },
542 )])
543 .unwrap();
544
545 let rows1_desc = converter_desc
546 .convert_columns(&[Arc::new(array1.clone())])
547 .unwrap();
548 let rows2_desc = converter_desc
549 .convert_columns(&[Arc::new(array2.clone())])
550 .unwrap();
551 let rows3_desc = converter_desc
552 .convert_columns(&[Arc::new(array3.clone())])
553 .unwrap();
554
555 assert!(
558 rows3_desc.row(0) < rows2_desc.row(0),
559 "cherry should come before banana in descending order (byte-wise)"
560 );
561 assert!(
562 rows2_desc.row(0) < rows1_desc.row(0),
563 "banana should come before apple in descending order (byte-wise)"
564 );
565 assert!(
566 rows3_desc.row(0) < rows1_desc.row(0),
567 "cherry should come before apple in descending order (byte-wise)"
568 );
569 }
570
571 #[test]
572 fn test_run_end_encoded_null_sorting() {
573 let array_with_nulls: RunArray<Int32Type> = vec![None, None].into_iter().collect();
576 let array_with_values: RunArray<Int32Type> = vec!["apple", "apple"].into_iter().collect();
577
578 let converter_nulls_first = RowConverter::new(vec![SortField::new_with_options(
580 DataType::RunEndEncoded(
581 Arc::new(Field::new(
582 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
583 DataType::Int32,
584 false,
585 )),
586 Arc::new(Field::new(
587 Field::REE_VALUES_FIELD_DEFAULT_NAME,
588 DataType::Utf8,
589 true,
590 )),
591 ),
592 arrow_schema::SortOptions {
593 descending: false,
594 nulls_first: true,
595 },
596 )])
597 .unwrap();
598
599 let rows_nulls = converter_nulls_first
600 .convert_columns(&[Arc::new(array_with_nulls.clone())])
601 .unwrap();
602 let rows_values = converter_nulls_first
603 .convert_columns(&[Arc::new(array_with_values.clone())])
604 .unwrap();
605
606 assert!(
608 rows_nulls.row(0) < rows_values.row(0),
609 "nulls should come before values when nulls_first=true"
610 );
611
612 let converter_nulls_last = RowConverter::new(vec![SortField::new_with_options(
614 DataType::RunEndEncoded(
615 Arc::new(Field::new(
616 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
617 DataType::Int32,
618 false,
619 )),
620 Arc::new(Field::new(
621 Field::REE_VALUES_FIELD_DEFAULT_NAME,
622 DataType::Utf8,
623 true,
624 )),
625 ),
626 arrow_schema::SortOptions {
627 descending: false,
628 nulls_first: false,
629 },
630 )])
631 .unwrap();
632
633 let rows_nulls_last = converter_nulls_last
634 .convert_columns(&[Arc::new(array_with_nulls.clone())])
635 .unwrap();
636 let rows_values_last = converter_nulls_last
637 .convert_columns(&[Arc::new(array_with_values.clone())])
638 .unwrap();
639
640 assert!(
642 rows_values_last.row(0) < rows_nulls_last.row(0),
643 "values should come before nulls when nulls_first=false"
644 );
645 }
646
647 #[test]
648 fn test_run_end_encoded_mixed_sorting() {
649 let array1: RunArray<Int32Type> = vec![Some("apple"), None].into_iter().collect();
652 let array2: RunArray<Int32Type> = vec![None, Some("banana")].into_iter().collect();
653 let array3: RunArray<Int32Type> =
654 vec![Some("cherry"), Some("cherry")].into_iter().collect();
655
656 let converter = RowConverter::new(vec![SortField::new_with_options(
657 DataType::RunEndEncoded(
658 Arc::new(Field::new(
659 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
660 DataType::Int32,
661 false,
662 )),
663 Arc::new(Field::new(
664 Field::REE_VALUES_FIELD_DEFAULT_NAME,
665 DataType::Utf8,
666 true,
667 )),
668 ),
669 arrow_schema::SortOptions {
670 descending: false,
671 nulls_first: true,
672 },
673 )])
674 .unwrap();
675
676 let rows1 = converter.convert_columns(&[Arc::new(array1)]).unwrap();
677 let rows2 = converter.convert_columns(&[Arc::new(array2)]).unwrap();
678 let rows3 = converter.convert_columns(&[Arc::new(array3)]).unwrap();
679
680 assert!(rows2.row(0) < rows1.row(0), "null should come before apple");
686 assert!(
687 rows1.row(0) < rows3.row(0),
688 "apple should come before cherry"
689 );
690
691 assert!(
693 rows1.row(1) < rows2.row(1),
694 "null should come before banana"
695 );
696 assert!(
697 rows2.row(1) < rows3.row(1),
698 "banana should come before cherry"
699 );
700 }
701
702 #[test]
703 fn test_run_end_encoded_empty() {
704 let values: Vec<&str> = vec![];
706 let array: RunArray<Int32Type> = values.into_iter().collect();
707
708 let converter = RowConverter::new(vec![SortField::new(DataType::RunEndEncoded(
709 Arc::new(Field::new(
710 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
711 DataType::Int32,
712 false,
713 )),
714 Arc::new(Field::new(
715 Field::REE_VALUES_FIELD_DEFAULT_NAME,
716 DataType::Utf8,
717 true,
718 )),
719 ))])
720 .unwrap();
721
722 let rows = converter.convert_columns(&[Arc::new(array)]).unwrap();
723 assert_eq!(rows.num_rows(), 0);
724
725 let arrays = converter.convert_rows(&rows).unwrap();
727 assert_eq!(arrays.len(), 1);
728 let result_ree = arrays[0].as_run::<Int32Type>();
730 assert_eq!(result_ree.len(), 0);
731 }
732
733 #[test]
734 fn test_run_end_encoded_round_trip_sliced() {
735 let values = Int64Array::from(vec![100, 200, 100, 300]);
736 let run_ends = vec![2, 3, 5, 6];
737 let array: RunArray<Int16Type> =
738 RunArray::try_new(&PrimitiveArray::from(run_ends), &values).unwrap();
739 let array = array.slice(2, 3);
740
741 assert_roundtrip(&array, DataType::Int16, DataType::Int64, None);
742 }
743}