1use std::fmt::Debug;
5use std::fmt::Display;
6use std::fmt::Formatter;
7use std::hash::Hash;
8use std::hash::Hasher;
9
10use prost::Message;
11use vortex_array::Array;
12use vortex_array::ArrayEq;
13use vortex_array::ArrayHash;
14use vortex_array::ArrayId;
15use vortex_array::ArrayParts;
16use vortex_array::ArrayRef;
17use vortex_array::ArrayView;
18use vortex_array::EqMode;
19use vortex_array::ExecutionCtx;
20use vortex_array::ExecutionResult;
21use vortex_array::IntoArray;
22use vortex_array::TypedArrayRef;
23use vortex_array::VortexSessionExecute;
24use vortex_array::array_slots;
25use vortex_array::arrays::DecimalArray;
26use vortex_array::arrays::ListViewArray;
27use vortex_array::arrays::Primitive;
28use vortex_array::arrays::PrimitiveArray;
29use vortex_array::arrays::VarBinViewArray;
30use vortex_array::arrays::listview::ListViewArraySlotsExt;
31use vortex_array::buffer::BufferHandle;
32use vortex_array::dtype::DType;
33use vortex_array::dtype::Nullability;
34use vortex_array::dtype::PType;
35use vortex_array::legacy_session;
36use vortex_array::serde::ArrayChildren;
37use vortex_array::validity::Validity;
38use vortex_array::vtable::VTable;
39use vortex_array::vtable::ValidityVTable;
40use vortex_error::VortexExpect as _;
41use vortex_error::VortexResult;
42use vortex_error::vortex_bail;
43use vortex_error::vortex_ensure;
44use vortex_error::vortex_panic;
45use vortex_session::VortexSession;
46use vortex_session::registry::CachedId;
47
48use crate::compress::runend_decode_decimal;
49use crate::compress::runend_decode_primitive;
50use crate::compress::runend_decode_varbinview;
51use crate::compress::runend_encode;
52use crate::decompress_bool::runend_decode_bools;
53use crate::ops::find_physical_index;
54use crate::ops::find_slice_end_index;
55use crate::rules::RULES;
56
57pub type RunEndArray = Array<RunEnd>;
59
60#[derive(Clone, prost::Message)]
61pub struct RunEndMetadata {
62 #[prost(enumeration = "PType", tag = "1")]
63 pub ends_ptype: i32,
64 #[prost(uint64, tag = "2")]
65 pub num_runs: u64,
66 #[prost(uint64, tag = "3")]
67 pub offset: u64,
68}
69
70impl ArrayHash for RunEndData {
71 fn array_hash<H: Hasher>(&self, state: &mut H, _accuracy: EqMode) {
72 self.offset.hash(state);
73 }
74}
75
76impl ArrayEq for RunEndData {
77 fn array_eq(&self, other: &Self, _accuracy: EqMode) -> bool {
78 self.offset == other.offset
79 }
80}
81
82impl VTable for RunEnd {
83 type TypedArrayData = RunEndData;
84
85 type OperationsVTable = Self;
86 type ValidityVTable = Self;
87
88 fn id(&self) -> ArrayId {
89 static ID: CachedId = CachedId::new("vortex.runend");
90 *ID
91 }
92
93 #[allow(clippy::disallowed_methods)]
94 fn validate(
95 &self,
96 data: &Self::TypedArrayData,
97 dtype: &DType,
98 len: usize,
99 slots: &[Option<ArrayRef>],
100 ) -> VortexResult<()> {
101 let run_end_slots = RunEndSlotsView::from_slots(slots);
102 let ends = run_end_slots.ends;
103 let values = run_end_slots.values;
104 let mut ctx = legacy_session().create_execution_ctx();
106 RunEndData::validate_parts(ends, values, data.offset, len, &mut ctx)?;
107 vortex_ensure!(
108 values.dtype() == dtype,
109 "expected dtype {}, got {}",
110 dtype,
111 values.dtype()
112 );
113 Ok(())
114 }
115
116 fn nbuffers(_array: ArrayView<'_, Self>) -> usize {
117 0
118 }
119
120 fn buffer(_array: ArrayView<'_, Self>, idx: usize) -> BufferHandle {
121 vortex_panic!("RunEndArray buffer index {idx} out of bounds")
122 }
123
124 fn buffer_name(_array: ArrayView<'_, Self>, idx: usize) -> Option<String> {
125 vortex_panic!("RunEndArray buffer_name index {idx} out of bounds")
126 }
127
128 fn with_buffers(
129 &self,
130 array: ArrayView<'_, Self>,
131 buffers: &[BufferHandle],
132 ) -> VortexResult<ArrayParts<Self>> {
133 vortex_array::vtable::with_empty_buffers(self, array, buffers)
134 }
135
136 fn serialize(
137 array: ArrayView<'_, Self>,
138 _session: &VortexSession,
139 ) -> VortexResult<Option<Vec<u8>>> {
140 Ok(Some(
141 RunEndMetadata {
142 ends_ptype: PType::try_from(array.ends().dtype())
143 .vortex_expect("Must be a valid PType") as i32,
144 num_runs: array.ends().len() as u64,
145 offset: array.offset() as u64,
146 }
147 .encode_to_vec(),
148 ))
149 }
150
151 fn deserialize(
152 &self,
153 dtype: &DType,
154 len: usize,
155 metadata: &[u8],
156 _buffers: &[BufferHandle],
157 children: &dyn ArrayChildren,
158 _session: &VortexSession,
159 ) -> VortexResult<ArrayParts<Self>> {
160 let metadata = RunEndMetadata::decode(metadata)?;
161 let ends_dtype = DType::Primitive(metadata.ends_ptype(), Nullability::NonNullable);
162 let runs = usize::try_from(metadata.num_runs).vortex_expect("Must be a valid usize");
163 let ends = children.get(0, &ends_dtype, runs)?;
164
165 let values = children.get(1, dtype, runs)?;
166 let offset = usize::try_from(metadata.offset).vortex_expect("Offset must be a valid usize");
167 let slots = RunEndSlots { ends, values }.into_slots();
168 let data = RunEndData::new(offset);
169 Ok(ArrayParts::new(self.clone(), dtype.clone(), len, data).with_slots(slots))
170 }
171
172 fn slot_name(_array: ArrayView<'_, Self>, idx: usize) -> String {
173 RunEndSlots::NAMES[idx].to_string()
174 }
175
176 fn reduce_parent(
177 array: ArrayView<'_, Self>,
178 parent: &ArrayRef,
179 child_idx: usize,
180 ) -> VortexResult<Option<ArrayRef>> {
181 RULES.evaluate(array, parent, child_idx)
182 }
183
184 fn execute(array: Array<Self>, ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult> {
185 run_end_canonicalize(&array, ctx).map(ExecutionResult::done)
186 }
187}
188
189#[array_slots(RunEnd)]
190pub struct RunEndSlots {
191 #[slot(0)]
193 pub ends: ArrayRef,
194 #[slot(1)]
196 pub values: ArrayRef,
197}
198
199#[derive(Clone, Debug)]
200pub struct RunEndData {
201 offset: usize,
202}
203
204impl Display for RunEndData {
205 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
206 write!(f, "offset: {}", self.offset)
207 }
208}
209
210pub struct RunEndDataParts {
211 pub ends: ArrayRef,
212 pub values: ArrayRef,
213 pub offset: usize,
214}
215
216pub trait RunEndArrayExt: RunEndArraySlotsExt {
217 fn offset(&self) -> usize {
218 self.offset
219 }
220
221 fn dtype(&self) -> &DType {
222 self.values().dtype()
223 }
224
225 fn find_physical_index(&self, index: usize, ctx: &mut ExecutionCtx) -> VortexResult<usize> {
226 find_physical_index(self.ends(), index + self.offset(), ctx)
227 }
228
229 fn find_slice_end_index(&self, index: usize, ctx: &mut ExecutionCtx) -> VortexResult<usize> {
230 find_slice_end_index(self.ends(), index + self.offset(), ctx)
231 }
232}
233
234impl<T: TypedArrayRef<RunEnd>> RunEndArrayExt for T {}
235
236#[derive(Clone, Debug)]
237pub struct RunEnd;
238
239impl RunEnd {
240 pub unsafe fn new_unchecked(
245 ends: ArrayRef,
246 values: ArrayRef,
247 offset: usize,
248 length: usize,
249 ) -> RunEndArray {
250 let dtype = values.dtype().clone();
251 let slots = RunEndSlots { ends, values }.into_slots();
252 let data = unsafe { RunEndData::new_unchecked(offset) };
253 unsafe {
254 Array::from_parts_unchecked(
255 ArrayParts::new(RunEnd, dtype, length, data).with_slots(slots),
256 )
257 }
258 }
259
260 pub fn try_new(
262 ends: ArrayRef,
263 values: ArrayRef,
264 ctx: &mut ExecutionCtx,
265 ) -> VortexResult<RunEndArray> {
266 let len = RunEndData::logical_len_from_ends(&ends, ctx)?;
267 RunEndData::validate_parts(&ends, &values, 0, len, ctx)?;
268 let dtype = values.dtype().clone();
269 let slots = RunEndSlots { ends, values }.into_slots();
270 let data = RunEndData::new(0);
271 Array::try_from_parts(ArrayParts::new(RunEnd, dtype, len, data).with_slots(slots))
272 }
273
274 pub fn try_new_offset_length(
276 ends: ArrayRef,
277 values: ArrayRef,
278 offset: usize,
279 length: usize,
280 ctx: &mut ExecutionCtx,
281 ) -> VortexResult<RunEndArray> {
282 RunEndData::validate_parts(&ends, &values, offset, length, ctx)?;
283 let dtype = values.dtype().clone();
284 let slots = RunEndSlots { ends, values }.into_slots();
285 let data = RunEndData::new(offset);
286 Array::try_from_parts(ArrayParts::new(RunEnd, dtype, length, data).with_slots(slots))
287 }
288
289 pub fn new(ends: ArrayRef, values: ArrayRef, ctx: &mut ExecutionCtx) -> RunEndArray {
291 Self::try_new(ends, values, ctx).vortex_expect("RunEndData is always valid")
292 }
293
294 pub fn encode(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<RunEndArray> {
296 if let Some(parray) = array.as_opt::<Primitive>() {
297 let (ends, values) = runend_encode(parray, ctx);
298 let ends = ends.into_array();
299 let len = array.len();
300 let dtype = values.dtype().clone();
301 let slots = RunEndSlots { ends, values }.into_slots();
302 let data = unsafe { RunEndData::new_unchecked(0) };
303 Array::try_from_parts(ArrayParts::new(RunEnd, dtype, len, data).with_slots(slots))
304 } else {
305 vortex_bail!("REE can only encode primitive arrays")
306 }
307 }
308}
309
310impl RunEndData {
311 fn logical_len_from_ends(ends: &ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<usize> {
312 if ends.is_empty() {
313 Ok(0)
314 } else {
315 usize::try_from(&ends.execute_scalar(ends.len() - 1, ctx)?)
316 }
317 }
318
319 pub fn validate_parts(
322 ends: &ArrayRef,
323 values: &ArrayRef,
324 offset: usize,
325 length: usize,
326 ctx: &mut ExecutionCtx,
327 ) -> VortexResult<()> {
328 vortex_ensure!(
330 ends.dtype().is_unsigned_int(),
331 "run ends must be unsigned integers, was {}",
332 ends.dtype(),
333 );
334 vortex_ensure!(
335 ends.len() == values.len(),
336 "run ends len != run values len, {} != {}",
337 ends.len(),
338 values.len()
339 );
340
341 if ends.is_empty() {
343 vortex_ensure!(
344 offset == 0,
345 "non-zero offset provided for empty RunEndArray"
346 );
347 return Ok(());
348 }
349
350 if length == 0 {
352 return Ok(());
353 }
354
355 #[cfg(debug_assertions)]
356 {
357 let pre_validation = ends.statistics().to_owned();
359
360 let is_sorted = ends
361 .statistics()
362 .compute_is_strict_sorted(ctx)
363 .unwrap_or(false);
364
365 ends.statistics().inherit(pre_validation.iter());
368 debug_assert!(is_sorted);
369 }
370
371 if !ends.is_host() {
373 return Ok(());
374 }
375
376 if offset != 0 && length != 0 {
378 let first_run_end = usize::try_from(&ends.execute_scalar(0, ctx)?)?;
379 if first_run_end < offset {
380 vortex_bail!("First run end {first_run_end} must be >= offset {offset}");
381 }
382 }
383
384 let last_run_end = usize::try_from(&ends.execute_scalar(ends.len() - 1, ctx)?)?;
385 let min_required_end = offset + length;
386 if last_run_end < min_required_end {
387 vortex_bail!("Last run end {last_run_end} must be >= offset+length {min_required_end}");
388 }
389
390 Ok(())
391 }
392}
393
394impl RunEndData {
395 pub fn new(offset: usize) -> Self {
425 Self { offset }
426 }
427
428 pub unsafe fn new_unchecked(offset: usize) -> Self {
438 Self { offset }
439 }
440
441 pub fn encode(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
443 if let Some(parray) = array.as_opt::<Primitive>() {
444 let (_ends, _values) = runend_encode(parray, ctx);
445 unsafe { Ok(Self::new_unchecked(0)) }
447 } else {
448 vortex_bail!("REE can only encode primitive arrays")
449 }
450 }
451
452 pub fn into_parts(self, ends: ArrayRef, values: ArrayRef) -> RunEndDataParts {
453 RunEndDataParts {
454 ends,
455 values,
456 offset: self.offset,
457 }
458 }
459}
460
461impl ValidityVTable<RunEnd> for RunEnd {
462 fn validity(array: ArrayView<'_, RunEnd>) -> VortexResult<Validity> {
463 Ok(match array.values().validity()? {
464 Validity::NonNullable | Validity::AllValid => Validity::AllValid,
465 Validity::AllInvalid => Validity::AllInvalid,
466 Validity::Array(values_validity) => Validity::Array(unsafe {
467 RunEnd::new_unchecked(
468 array.ends().clone(),
469 values_validity,
470 array.offset(),
471 array.len(),
472 )
473 .into_array()
474 }),
475 })
476 }
477}
478
479pub(super) fn run_end_canonicalize(
480 array: &RunEndArray,
481 ctx: &mut ExecutionCtx,
482) -> VortexResult<ArrayRef> {
483 let pends = array.ends().clone().execute_as("ends", ctx)?;
484
485 Ok(match array.dtype() {
486 DType::Bool(_) => {
487 let bools = array.values().clone().execute_as("values", ctx)?;
488 runend_decode_bools(pends, bools, array.offset(), array.len(), ctx)?
489 }
490 DType::Primitive(..) => {
491 let pvalues = array.values().clone().execute_as("values", ctx)?;
492 runend_decode_primitive(pends, pvalues, array.offset(), array.len(), ctx)?.into_array()
493 }
494 DType::Decimal(..) => {
495 let values = array
496 .values()
497 .clone()
498 .execute_as::<DecimalArray>("values", ctx)?;
499 runend_decode_decimal(pends, values, array.offset(), array.len(), ctx)?.into_array()
500 }
501 DType::Utf8(_) | DType::Binary(_) => {
502 let values = array
503 .values()
504 .clone()
505 .execute_as::<VarBinViewArray>("values", ctx)?;
506 runend_decode_varbinview(pends, values, array.offset(), array.len(), ctx)?.into_array()
507 }
508 DType::List(..) => {
509 let values = array
510 .values()
511 .clone()
512 .execute_as::<ListViewArray>("values", ctx)?;
513 runend_decode_listview(pends, values, array.offset(), array.len())?.into_array()
514 }
515 _ => vortex_bail!("Unsupported RunEnd value type: {}", array.dtype()),
516 })
517}
518
519fn runend_decode_listview(
520 ends: PrimitiveArray,
521 values: ListViewArray,
522 offset: usize,
523 length: usize,
524) -> VortexResult<ListViewArray> {
525 let validity = match values.validity()? {
526 Validity::NonNullable => Validity::NonNullable,
527 Validity::AllValid => Validity::AllValid,
528 Validity::AllInvalid => Validity::AllInvalid,
529 Validity::Array(validity) => Validity::Array(unsafe {
530 RunEnd::new_unchecked(ends.clone().into_array(), validity, offset, length).into_array()
531 }),
532 };
533
534 Ok(unsafe {
537 ListViewArray::new_unchecked(
538 values.elements().clone(),
539 RunEnd::new_unchecked(
540 ends.clone().into_array(),
541 values.offsets().clone(),
542 offset,
543 length,
544 )
545 .into_array(),
546 RunEnd::new_unchecked(ends.into_array(), values.sizes().clone(), offset, length)
547 .into_array(),
548 validity,
549 )
550 })
551}
552
553#[cfg(test)]
554mod tests {
555 use std::sync::Arc;
556 use std::sync::LazyLock;
557
558 use vortex_array::IntoArray;
559 use vortex_array::VortexSessionExecute;
560 use vortex_array::arrays::DecimalArray;
561 use vortex_array::arrays::DictArray;
562 use vortex_array::arrays::ListArray;
563 use vortex_array::arrays::ListViewArray;
564 use vortex_array::arrays::VarBinViewArray;
565 use vortex_array::arrays::listview::ListViewArraySlotsExt;
566 use vortex_array::assert_arrays_eq;
567 use vortex_array::builders::VarBinBuilder;
568 use vortex_array::dtype::DType;
569 use vortex_array::dtype::DecimalDType;
570 use vortex_array::dtype::Nullability;
571 use vortex_array::dtype::PType;
572 use vortex_array::dtype::i256;
573 use vortex_array::validity::Validity;
574 use vortex_buffer::buffer;
575 use vortex_error::VortexResult;
576 use vortex_session::VortexSession;
577
578 use crate::RunEnd;
579
580 static SESSION: LazyLock<VortexSession> = LazyLock::new(|| {
581 let session = vortex_array::array_session();
582 crate::initialize(&session);
583 session
584 });
585
586 #[test]
587 fn test_runend_constructor() {
588 let mut ctx = SESSION.create_execution_ctx();
589 let arr = RunEnd::new(
590 buffer![2u32, 5, 10].into_array(),
591 buffer![1i32, 2, 3].into_array(),
592 &mut ctx,
593 );
594 assert_eq!(arr.len(), 10);
595 assert_eq!(
596 arr.dtype(),
597 &DType::Primitive(PType::I32, Nullability::NonNullable)
598 );
599
600 let expected = buffer![1, 1, 2, 2, 2, 3, 3, 3, 3, 3].into_array();
604 assert_arrays_eq!(arr.into_array(), expected, &mut ctx);
605 }
606
607 #[test]
608 fn test_runend_utf8() {
609 let mut ctx = SESSION.create_execution_ctx();
610 let values =
611 VarBinViewArray::from_iter_nullable_str([Some("a"), None, Some("c")]).into_array();
612 let arr = RunEnd::new(buffer![2u32, 5, 10].into_array(), values, &mut ctx);
613 assert_eq!(arr.len(), 10);
614 assert_eq!(arr.dtype(), &DType::Utf8(Nullability::Nullable));
615
616 let expected = VarBinViewArray::from_iter_nullable_str([
617 Some("a"),
618 Some("a"),
619 None,
620 None,
621 None,
622 Some("c"),
623 Some("c"),
624 Some("c"),
625 Some("c"),
626 Some("c"),
627 ])
628 .into_array();
629 let mut builder = VarBinBuilder::<i32>::with_capacity_in(
630 arr.dtype().clone(),
631 arr.len(),
632 vortex_buffer::BufferAllocatorRef::static_ref(),
633 );
634 arr.append_to_builder(&mut builder, &mut ctx).unwrap();
635 assert_arrays_eq!(builder.finish_into_varbin(), expected, &mut ctx);
636 assert_arrays_eq!(arr.into_array(), expected, &mut ctx);
637 }
638
639 #[test]
640 fn test_runend_decimal() {
641 let mut ctx = SESSION.create_execution_ctx();
642 let decimal_dtype = DecimalDType::new(10, 2);
643 let values = DecimalArray::from_iter([12345i64, 67890, -12300], decimal_dtype).into_array();
644 let arr = RunEnd::new(buffer![2u32, 5, 10].into_array(), values, &mut ctx);
645 assert_eq!(arr.len(), 10);
646 assert_eq!(
647 arr.dtype(),
648 &DType::Decimal(decimal_dtype, Nullability::NonNullable)
649 );
650
651 let expected = DecimalArray::from_iter(
652 [
653 12345i64, 12345, 67890, 67890, 67890, -12300, -12300, -12300, -12300, -12300,
654 ],
655 decimal_dtype,
656 )
657 .into_array();
658 assert_arrays_eq!(arr.into_array(), expected, &mut ctx);
659 }
660
661 #[test]
662 fn test_runend_list_i64() {
663 let mut ctx = SESSION.create_execution_ctx();
664 let values = ListArray::from_iter_slow::<u32, _>(
665 vec![vec![1i64, 2], vec![3], vec![4, 5, 6]],
666 Arc::new(DType::Primitive(PType::I64, Nullability::NonNullable)),
667 )
668 .unwrap()
669 .into_array();
670 let arr = RunEnd::new(buffer![2u32, 5, 10].into_array(), values, &mut ctx);
671
672 let expected = ListArray::from_iter_slow::<u32, _>(
673 vec![
674 vec![1i64, 2],
675 vec![1, 2],
676 vec![3],
677 vec![3],
678 vec![3],
679 vec![4, 5, 6],
680 vec![4, 5, 6],
681 vec![4, 5, 6],
682 vec![4, 5, 6],
683 vec![4, 5, 6],
684 ],
685 Arc::new(DType::Primitive(PType::I64, Nullability::NonNullable)),
686 )
687 .unwrap()
688 .into_array();
689 assert_arrays_eq!(arr.into_array(), expected, &mut ctx);
690 }
691
692 #[test]
693 fn test_runend_nullable_decimal() {
694 let mut ctx = SESSION.create_execution_ctx();
695 let decimal_dtype = DecimalDType::new(10, 2);
696 let values =
697 DecimalArray::from_option_iter([Some(12345i64), None, Some(-12300)], decimal_dtype)
698 .into_array();
699 let arr = RunEnd::new(buffer![2u32, 5, 10].into_array(), values, &mut ctx);
700 assert_eq!(arr.len(), 10);
701 assert_eq!(
702 arr.dtype(),
703 &DType::Decimal(decimal_dtype, Nullability::Nullable)
704 );
705
706 let expected = DecimalArray::from_option_iter(
707 [
708 Some(12345i64),
709 Some(12345),
710 None,
711 None,
712 None,
713 Some(-12300),
714 Some(-12300),
715 Some(-12300),
716 Some(-12300),
717 Some(-12300),
718 ],
719 decimal_dtype,
720 )
721 .into_array();
722 assert_arrays_eq!(arr.into_array(), expected, &mut ctx);
723 }
724
725 #[test]
726 fn test_runend_list_bool() {
727 let mut ctx = SESSION.create_execution_ctx();
728 let values = ListArray::from_iter_slow::<u32, _>(
729 vec![vec![true, false], vec![false], vec![true, true, false]],
730 Arc::new(DType::Bool(Nullability::NonNullable)),
731 )
732 .unwrap()
733 .into_array();
734 let arr = RunEnd::new(buffer![2u32, 5, 10].into_array(), values, &mut ctx);
735
736 let expected = ListArray::from_iter_slow::<u32, _>(
737 vec![
738 vec![true, false],
739 vec![true, false],
740 vec![false],
741 vec![false],
742 vec![false],
743 vec![true, true, false],
744 vec![true, true, false],
745 vec![true, true, false],
746 vec![true, true, false],
747 vec![true, true, false],
748 ],
749 Arc::new(DType::Bool(Nullability::NonNullable)),
750 )
751 .unwrap()
752 .into_array();
753 assert_arrays_eq!(arr.into_array(), expected, &mut ctx);
754 }
755
756 #[test]
757 fn test_runend_list_utf8() {
758 let mut ctx = SESSION.create_execution_ctx();
759 let values = ListArray::try_new(
760 VarBinViewArray::from_iter_str(["a", "b", "c", "d", "e", "f"]).into_array(),
761 buffer![0u32, 2, 3, 6].into_array(),
762 Validity::NonNullable,
763 )
764 .unwrap()
765 .into_array();
766 let arr = RunEnd::new(buffer![2u32, 5, 10].into_array(), values, &mut ctx);
767
768 let expected = ListArray::try_new(
769 VarBinViewArray::from_iter_str([
770 "a", "b", "a", "b", "c", "c", "c", "d", "e", "f", "d", "e", "f", "d", "e", "f",
771 "d", "e", "f", "d", "e", "f",
772 ])
773 .into_array(),
774 buffer![0u32, 2, 4, 5, 6, 7, 10, 13, 16, 19, 22].into_array(),
775 Validity::NonNullable,
776 )
777 .unwrap()
778 .into_array();
779 assert_arrays_eq!(arr.into_array(), expected, &mut ctx);
780 }
781
782 #[test]
783 fn test_runend_list_canonicalizes_to_runend_listview_slots() -> VortexResult<()> {
784 let mut ctx = SESSION.create_execution_ctx();
785 let values = ListArray::try_new(
786 buffer![1i64, 2, 3, 4, 5, 6].into_array(),
787 buffer![0u32, 2, 3, 6].into_array(),
788 Validity::from_iter([true, false, true]),
789 )?
790 .into_array();
791 let arr = RunEnd::try_new(buffer![2u32, 5, 6].into_array(), values, &mut ctx)?;
792
793 let listview = arr
794 .clone()
795 .into_array()
796 .execute::<ListViewArray>(&mut ctx)?;
797 assert!(listview.offsets().is::<RunEnd>());
798 assert!(listview.sizes().is::<RunEnd>());
799 match listview.validity()? {
800 Validity::Array(validity) => assert!(validity.is::<RunEnd>()),
801 validity => panic!("expected array-backed validity, got {validity:?}"),
802 }
803
804 let expected = ListArray::try_new(
805 buffer![1i64, 2, 1, 2, 3, 3, 3, 4, 5, 6].into_array(),
806 buffer![0u32, 2, 4, 5, 6, 7, 10].into_array(),
807 Validity::from_iter([true, true, false, false, false, true]),
808 )?
809 .into_array();
810 assert_arrays_eq!(arr.into_array(), expected, &mut ctx);
811 Ok(())
812 }
813
814 #[test]
815 fn test_runend_dict() {
816 let mut ctx = SESSION.create_execution_ctx();
817 let dict_values = VarBinViewArray::from_iter_str(["x", "y", "z"]).into_array();
818 let dict_codes = buffer![0u32, 1, 2].into_array();
819 let dict = DictArray::try_new(dict_codes, dict_values).unwrap();
820
821 let arr = RunEnd::try_new(
822 buffer![2u32, 5, 10].into_array(),
823 dict.into_array(),
824 &mut ctx,
825 )
826 .unwrap();
827 assert_eq!(arr.len(), 10);
828
829 let expected =
830 VarBinViewArray::from_iter_str(["x", "x", "y", "y", "y", "z", "z", "z", "z", "z"])
831 .into_array();
832 assert_arrays_eq!(arr.into_array(), expected, &mut ctx);
833 }
834
835 #[test]
836 fn test_runend_decimal_i128() -> VortexResult<()> {
837 let mut ctx = SESSION.create_execution_ctx();
838 let decimal_dtype = DecimalDType::new(20, 2);
839 let values = DecimalArray::from_iter([12_345i128, -67_890, 100], decimal_dtype);
840 let arr = RunEnd::try_new(
841 buffer![2u32, 5, 6].into_array(),
842 values.into_array(),
843 &mut ctx,
844 )?;
845
846 let decoded = arr.into_array().execute::<DecimalArray>(&mut ctx)?;
847 let expected = DecimalArray::from_iter(
848 [12_345i128, 12_345, -67_890, -67_890, -67_890, 100],
849 decimal_dtype,
850 );
851 assert_arrays_eq!(decoded, expected, &mut ctx);
852 Ok(())
853 }
854
855 #[test]
856 fn test_runend_decimal_nullable() -> VortexResult<()> {
857 let mut ctx = SESSION.create_execution_ctx();
858 let decimal_dtype = DecimalDType::new(20, 2);
859 let values =
860 DecimalArray::from_option_iter([Some(12_345i128), None, Some(-67_890)], decimal_dtype);
861 let arr = RunEnd::try_new(
862 buffer![2u32, 5, 7].into_array(),
863 values.into_array(),
864 &mut ctx,
865 )?;
866
867 let decoded = arr.into_array().execute::<DecimalArray>(&mut ctx)?;
868 let expected = DecimalArray::from_option_iter(
869 [
870 Some(12_345i128),
871 Some(12_345),
872 None,
873 None,
874 None,
875 Some(-67_890),
876 Some(-67_890),
877 ],
878 decimal_dtype,
879 );
880 assert_arrays_eq!(decoded, expected, &mut ctx);
881 Ok(())
882 }
883
884 #[test]
885 fn test_runend_decimal_slice() -> VortexResult<()> {
886 let mut ctx = SESSION.create_execution_ctx();
887 let decimal_dtype = DecimalDType::new(20, 2);
888 let values = DecimalArray::from_iter([100i128, 200, 300], decimal_dtype);
889 let arr = RunEnd::try_new(
890 buffer![3u32, 5, 10].into_array(),
891 values.into_array(),
892 &mut ctx,
893 )?;
894
895 let sliced = arr.slice(2..8)?;
896 let decoded = sliced.execute::<DecimalArray>(&mut ctx)?;
897 let expected = DecimalArray::from_iter([100i128, 200, 200, 300, 300, 300], decimal_dtype);
898 assert_arrays_eq!(decoded, expected, &mut ctx);
899 Ok(())
900 }
901
902 #[test]
903 fn test_runend_decimal_i256() -> VortexResult<()> {
904 let mut ctx = SESSION.create_execution_ctx();
905 let decimal_dtype = DecimalDType::new(40, 4);
906 let first = i256::from_i128(123_456);
907 let second = i256::from_i128(-789_012);
908 let values = DecimalArray::from_iter([first, second], decimal_dtype);
909 let arr = RunEnd::try_new(buffer![2u32, 5].into_array(), values.into_array(), &mut ctx)?;
910
911 let decoded = arr.into_array().execute::<DecimalArray>(&mut ctx)?;
912 let expected =
913 DecimalArray::from_iter([first, first, second, second, second], decimal_dtype);
914 assert_arrays_eq!(decoded, expected, &mut ctx);
915 Ok(())
916 }
917}