1use std::any::TypeId;
7use std::sync::Arc;
8
9use vortex_buffer::BitBuffer;
10use vortex_buffer::Buffer;
11use vortex_error::VortexExpect;
12use vortex_error::VortexResult;
13use vortex_error::vortex_ensure;
14use vortex_error::vortex_panic;
15
16use crate::ArrayRef;
17use crate::ArraySlots;
18use crate::Executable;
19use crate::ExecutionCtx;
20use crate::IntoArray;
21use crate::array::ArrayView;
22use crate::array::VTable;
23use crate::array::child_to_validity;
24use crate::arrays::Bool;
25use crate::arrays::BoolArray;
26use crate::arrays::Decimal;
27use crate::arrays::DecimalArray;
28use crate::arrays::Extension;
29use crate::arrays::ExtensionArray;
30use crate::arrays::FixedSizeList;
31use crate::arrays::FixedSizeListArray;
32use crate::arrays::ListView;
33use crate::arrays::ListViewArray;
34use crate::arrays::Map;
35use crate::arrays::MapArray;
36use crate::arrays::Null;
37use crate::arrays::NullArray;
38use crate::arrays::Primitive;
39use crate::arrays::PrimitiveArray;
40use crate::arrays::Struct;
41use crate::arrays::StructArray;
42use crate::arrays::Union;
43use crate::arrays::UnionArray;
44use crate::arrays::VarBinView;
45use crate::arrays::VarBinViewArray;
46use crate::arrays::Variant;
47use crate::arrays::VariantArray;
48use crate::arrays::bool::BoolDataParts;
49use crate::arrays::decimal::DecimalDataParts;
50use crate::arrays::extension::ExtensionArrayExt;
51use crate::arrays::fixed_size_list::FixedSizeListArrayExt;
52use crate::arrays::listview::ListViewDataParts;
53use crate::arrays::listview::ListViewRebuildMode;
54use crate::arrays::map::MapArrayExt;
55use crate::arrays::map::MapArraySlotsExt;
56use crate::arrays::primitive::PrimitiveDataParts;
57use crate::arrays::struct_::StructDataParts;
58use crate::arrays::union::UnionDataParts;
59use crate::arrays::varbinview::VarBinViewDataParts;
60use crate::arrays::variant::VariantArraySlotsExt;
61use crate::dtype::DType;
62use crate::dtype::NativePType;
63use crate::dtype::Nullability;
64use crate::dtype::PType;
65use crate::match_each_decimal_value_type;
66use crate::match_each_native_ptype;
67use crate::matcher::Matcher;
68use crate::validity::Validity;
69
70#[derive(Debug, Clone)]
134pub enum Canonical {
135 Null(NullArray),
136 Bool(BoolArray),
137 Primitive(PrimitiveArray),
138 Decimal(DecimalArray),
139 VarBinView(VarBinViewArray),
140 List(ListViewArray),
141 Map(MapArray),
142 FixedSizeList(FixedSizeListArray),
143 Struct(StructArray),
144 Union(UnionArray),
145 Extension(ExtensionArray),
147 Variant(VariantArray),
149}
150
151macro_rules! match_each_canonical {
153 ($self:expr, | $ident:ident | $eval:expr) => {{
154 match $self {
155 Canonical::Null($ident) => $eval,
156 Canonical::Bool($ident) => $eval,
157 Canonical::Primitive($ident) => $eval,
158 Canonical::Decimal($ident) => $eval,
159 Canonical::VarBinView($ident) => $eval,
160 Canonical::List($ident) => $eval,
161 Canonical::Map($ident) => $eval,
162 Canonical::FixedSizeList($ident) => $eval,
163 Canonical::Struct($ident) => $eval,
164 Canonical::Union($ident) => $eval,
165 Canonical::Variant($ident) => $eval,
166 Canonical::Extension($ident) => $eval,
167 }
168 }};
169}
170
171impl Canonical {
172 pub fn empty(dtype: &DType) -> Canonical {
174 match dtype {
175 DType::Null => Canonical::Null(NullArray::new(0)),
176 DType::Bool(n) => Canonical::Bool(unsafe {
177 BoolArray::new_unchecked(BitBuffer::empty(), Validity::from(n))
178 }),
179 DType::Primitive(ptype, n) => {
180 match_each_native_ptype!(ptype, |P| {
181 Canonical::Primitive(unsafe {
182 PrimitiveArray::new_unchecked(Buffer::<P>::empty(), Validity::from(n))
183 })
184 })
185 }
186 DType::Decimal(decimal_type, n) => {
187 match_each_decimal_value_type!(
188 DecimalType::smallest_decimal_value_type(decimal_type),
189 |D| {
190 Canonical::Decimal(unsafe {
191 DecimalArray::new_unchecked::<D>(
192 Buffer::empty(),
193 *decimal_type,
194 Validity::from(n),
195 )
196 })
197 }
198 )
199 }
200 DType::Utf8(n) => Canonical::VarBinView(unsafe {
201 VarBinViewArray::new_unchecked(
202 Buffer::empty(),
203 Arc::new([]),
204 dtype.clone(),
205 Validity::from(n),
206 )
207 }),
208 DType::Binary(n) => Canonical::VarBinView(unsafe {
209 VarBinViewArray::new_unchecked(
210 Buffer::empty(),
211 Arc::new([]),
212 dtype.clone(),
213 Validity::from(n),
214 )
215 }),
216 DType::List(dtype, n) => Canonical::List(unsafe {
217 ListViewArray::new_unchecked(
218 Canonical::empty(dtype).into_array(),
219 Canonical::empty(&DType::Primitive(PType::U8, Nullability::NonNullable))
220 .into_array(),
221 Canonical::empty(&DType::Primitive(PType::U8, Nullability::NonNullable))
222 .into_array(),
223 Validity::from(n),
224 )
225 .with_zero_copy_to_list(true)
227 }),
228 DType::Map(map_dtype, nullability) => Canonical::Map(MapArray::new(
229 map_dtype.clone(),
230 Canonical::empty(&DType::List(
231 Arc::new(map_dtype.entries_dtype()),
232 *nullability,
233 ))
234 .into_listview(),
235 )),
236 DType::FixedSizeList(elem_dtype, list_size, null) => Canonical::FixedSizeList(unsafe {
237 FixedSizeListArray::new_unchecked(
238 Canonical::empty(elem_dtype).into_array(),
239 *list_size,
240 Validity::from(null),
241 0,
242 )
243 }),
244 DType::Struct(struct_dtype, n) => Canonical::Struct(unsafe {
245 StructArray::new_unchecked(
246 struct_dtype
247 .fields()
248 .map(|f| Canonical::empty(&f).into_array())
249 .collect::<Vec<_>>(),
250 struct_dtype.clone(),
251 0,
252 Validity::from(n),
253 )
254 }),
255 DType::Union(variants, nullability) => {
256 Canonical::Union(UnionArray::empty(variants.clone(), *nullability))
257 }
258 DType::Variant(_) => {
259 vortex_panic!(InvalidArgument: "Canonical empty is not supported for Variant")
260 }
261 DType::Extension(ext_dtype) => Canonical::Extension(ExtensionArray::new(
262 ext_dtype.clone(),
263 Canonical::empty(ext_dtype.storage_dtype()).into_array(),
264 )),
265 }
266 }
267
268 pub fn len(&self) -> usize {
269 match_each_canonical!(self, |arr| arr.len())
270 }
271
272 pub fn dtype(&self) -> &DType {
273 match_each_canonical!(self, |arr| arr.dtype())
274 }
275
276 pub fn is_empty(&self) -> bool {
277 match_each_canonical!(self, |arr| arr.is_empty())
278 }
279}
280
281impl Canonical {
282 pub fn compact(&self, ctx: &mut ExecutionCtx) -> VortexResult<Canonical> {
290 match self {
291 Canonical::Bool(array) => Ok(Canonical::Bool(array.trim_bits()?)),
292 Canonical::VarBinView(array) => Ok(Canonical::VarBinView(array.compact_buffers(ctx)?)),
293 Canonical::List(array) => Ok(Canonical::List(
294 array.rebuild(ListViewRebuildMode::TrimElements, ctx)?,
295 )),
296 Canonical::Map(array) => Ok(Canonical::Map(MapArray::new(
297 array.map_dtype().clone(),
298 array
299 .entries()
300 .as_::<ListView>()
301 .into_owned()
302 .rebuild(ListViewRebuildMode::TrimElements, ctx)?,
303 ))),
304 _ => Ok(self.clone()),
305 }
306 }
307}
308
309impl Canonical {
311 pub fn as_null(&self) -> &NullArray {
312 if let Canonical::Null(a) = self {
313 a
314 } else {
315 vortex_panic!("Cannot get NullArray from {:?}", &self)
316 }
317 }
318
319 pub fn into_null(self) -> NullArray {
320 if let Canonical::Null(a) = self {
321 a
322 } else {
323 vortex_panic!("Cannot unwrap NullArray from {:?}", &self)
324 }
325 }
326
327 pub fn as_bool(&self) -> &BoolArray {
328 if let Canonical::Bool(a) = self {
329 a
330 } else {
331 vortex_panic!("Cannot get BoolArray from {:?}", &self)
332 }
333 }
334
335 pub fn into_bool(self) -> BoolArray {
336 if let Canonical::Bool(a) = self {
337 a
338 } else {
339 vortex_panic!("Cannot unwrap BoolArray from {:?}", &self)
340 }
341 }
342
343 pub fn as_primitive(&self) -> &PrimitiveArray {
344 if let Canonical::Primitive(a) = self {
345 a
346 } else {
347 vortex_panic!("Cannot get PrimitiveArray from {:?}", &self)
348 }
349 }
350
351 pub fn into_primitive(self) -> PrimitiveArray {
352 if let Canonical::Primitive(a) = self {
353 a
354 } else {
355 vortex_panic!("Cannot unwrap PrimitiveArray from {:?}", &self)
356 }
357 }
358
359 pub fn as_decimal(&self) -> &DecimalArray {
360 if let Canonical::Decimal(a) = self {
361 a
362 } else {
363 vortex_panic!("Cannot get DecimalArray from {:?}", &self)
364 }
365 }
366
367 pub fn into_decimal(self) -> DecimalArray {
368 if let Canonical::Decimal(a) = self {
369 a
370 } else {
371 vortex_panic!("Cannot unwrap DecimalArray from {:?}", &self)
372 }
373 }
374
375 pub fn as_varbinview(&self) -> &VarBinViewArray {
376 if let Canonical::VarBinView(a) = self {
377 a
378 } else {
379 vortex_panic!("Cannot get VarBinViewArray from {:?}", &self)
380 }
381 }
382
383 pub fn into_varbinview(self) -> VarBinViewArray {
384 if let Canonical::VarBinView(a) = self {
385 a
386 } else {
387 vortex_panic!("Cannot unwrap VarBinViewArray from {:?}", &self)
388 }
389 }
390
391 pub fn as_listview(&self) -> &ListViewArray {
392 if let Canonical::List(a) = self {
393 a
394 } else {
395 vortex_panic!("Cannot get ListArray from {:?}", &self)
396 }
397 }
398
399 pub fn into_listview(self) -> ListViewArray {
400 if let Canonical::List(a) = self {
401 a
402 } else {
403 vortex_panic!("Cannot unwrap ListArray from {:?}", &self)
404 }
405 }
406
407 pub fn as_map(&self) -> &MapArray {
408 if let Canonical::Map(a) = self {
409 a
410 } else {
411 vortex_panic!("Cannot get MapArray from {:?}", &self)
412 }
413 }
414
415 pub fn into_map(self) -> MapArray {
416 if let Canonical::Map(a) = self {
417 a
418 } else {
419 vortex_panic!("Cannot unwrap MapArray from {:?}", &self)
420 }
421 }
422
423 pub fn as_fixed_size_list(&self) -> &FixedSizeListArray {
424 if let Canonical::FixedSizeList(a) = self {
425 a
426 } else {
427 vortex_panic!("Cannot get FixedSizeListArray from {:?}", &self)
428 }
429 }
430
431 pub fn into_fixed_size_list(self) -> FixedSizeListArray {
432 if let Canonical::FixedSizeList(a) = self {
433 a
434 } else {
435 vortex_panic!("Cannot unwrap FixedSizeListArray from {:?}", &self)
436 }
437 }
438
439 pub fn as_struct(&self) -> &StructArray {
440 if let Canonical::Struct(a) = self {
441 a
442 } else {
443 vortex_panic!("Cannot get StructArray from {:?}", &self)
444 }
445 }
446
447 pub fn into_struct(self) -> StructArray {
448 if let Canonical::Struct(a) = self {
449 a
450 } else {
451 vortex_panic!("Cannot unwrap StructArray from {:?}", &self)
452 }
453 }
454
455 pub fn as_union(&self) -> &UnionArray {
457 if let Canonical::Union(a) = self {
458 a
459 } else {
460 vortex_panic!("Cannot get UnionArray from {:?}", &self)
461 }
462 }
463
464 pub fn into_union(self) -> UnionArray {
466 if let Canonical::Union(a) = self {
467 a
468 } else {
469 vortex_panic!("Cannot unwrap UnionArray from {:?}", &self)
470 }
471 }
472
473 pub fn as_extension(&self) -> &ExtensionArray {
474 if let Canonical::Extension(a) = self {
475 a
476 } else {
477 vortex_panic!("Cannot get ExtensionArray from {:?}", &self)
478 }
479 }
480
481 pub fn into_extension(self) -> ExtensionArray {
482 if let Canonical::Extension(a) = self {
483 a
484 } else {
485 vortex_panic!("Cannot unwrap ExtensionArray from {:?}", &self)
486 }
487 }
488}
489
490impl IntoArray for Canonical {
491 fn into_array(self) -> ArrayRef {
492 match_each_canonical!(self, |arr| arr.into_array())
493 }
494}
495
496impl From<Canonical> for ArrayRef {
497 fn from(value: Canonical) -> Self {
498 match_each_canonical!(value, |arr| arr.into_array())
499 }
500}
501
502impl Executable for Canonical {
508 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
509 let result = array.execute_until::<AnyCanonical>(ctx)?;
510 Ok(result
511 .as_opt::<AnyCanonical>()
512 .map(Canonical::from)
513 .vortex_expect("execute_until::<AnyCanonical> must return a canonical array"))
514 }
515}
516
517pub struct CanonicalValidity(pub Canonical);
522
523impl Executable for CanonicalValidity {
524 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
525 match array.execute::<Canonical>(ctx)? {
526 n @ Canonical::Null(_) => Ok(CanonicalValidity(n)),
527 Canonical::Bool(b) => {
528 let validity = child_to_validity(b.slots()[0].as_ref(), b.dtype().nullability());
529 let len = b.len();
530 let BoolDataParts { bits, meta } = b.into_data().into_parts(len);
531 Ok(CanonicalValidity(Canonical::Bool(
532 BoolArray::try_new_from_handle(
533 bits,
534 meta.offset(),
535 meta.len(),
536 validity.execute(ctx)?,
537 )?,
538 )))
539 }
540 Canonical::Primitive(p) => {
541 let PrimitiveDataParts {
542 ptype,
543 buffer,
544 validity,
545 } = p.into_data_parts();
546 Ok(CanonicalValidity(Canonical::Primitive(unsafe {
547 PrimitiveArray::new_unchecked_from_handle(buffer, ptype, validity.execute(ctx)?)
548 })))
549 }
550 Canonical::Decimal(d) => {
551 let DecimalDataParts {
552 decimal_dtype,
553 values,
554 values_type,
555 validity,
556 } = d.into_data_parts();
557 Ok(CanonicalValidity(Canonical::Decimal(unsafe {
558 DecimalArray::new_unchecked_handle(
559 values,
560 values_type,
561 decimal_dtype,
562 validity.execute(ctx)?,
563 )
564 })))
565 }
566 Canonical::VarBinView(vbv) => {
567 let VarBinViewDataParts {
568 dtype,
569 buffers,
570 views,
571 validity,
572 } = vbv.into_data_parts();
573 Ok(CanonicalValidity(Canonical::VarBinView(unsafe {
574 VarBinViewArray::new_handle_unchecked(
575 views,
576 buffers,
577 dtype,
578 validity.execute(ctx)?,
579 )
580 })))
581 }
582 Canonical::List(l) => {
583 let zctl = l.is_zero_copy_to_list();
584 let ListViewDataParts {
585 elements,
586 offsets,
587 sizes,
588 validity,
589 ..
590 } = l.into_data_parts();
591 Ok(CanonicalValidity(Canonical::List(unsafe {
592 ListViewArray::new_unchecked(elements, offsets, sizes, validity.execute(ctx)?)
593 .with_zero_copy_to_list(zctl)
594 })))
595 }
596 Canonical::Map(map) => {
597 let map_dtype = map.map_dtype().clone();
598 let entries = map.entries().clone();
599 Ok(CanonicalValidity(Canonical::Map(MapArray::new(
600 map_dtype,
601 entries.execute::<CanonicalValidity>(ctx)?.0.into_listview(),
602 ))))
603 }
604 Canonical::FixedSizeList(fsl) => {
605 let list_size = fsl.list_size();
606 let len = fsl.len();
607 let parts = fsl.into_data_parts();
608 let elements = parts.elements;
609 let validity = parts.validity;
610 Ok(CanonicalValidity(Canonical::FixedSizeList(
611 FixedSizeListArray::new(elements, list_size, validity.execute(ctx)?, len),
612 )))
613 }
614 Canonical::Struct(st) => {
615 let len = st.len();
616 let StructDataParts {
617 struct_fields,
618 fields,
619 validity,
620 } = st.into_data_parts();
621 Ok(CanonicalValidity(Canonical::Struct(unsafe {
622 StructArray::new_unchecked(fields, struct_fields, len, validity.execute(ctx)?)
623 })))
624 }
625 Canonical::Union(union) => {
626 let UnionDataParts {
627 variants,
628 type_ids,
629 children,
630 } = union.into_data_parts();
631 let type_ids = type_ids.execute::<CanonicalValidity>(ctx)?.0.into_array();
632
633 Ok(CanonicalValidity(Canonical::Union(unsafe {
634 UnionArray::new_unchecked(type_ids, variants, children.iter().cloned())
635 })))
636 }
637 Canonical::Extension(ext) => Ok(CanonicalValidity(Canonical::Extension(
638 ExtensionArray::new(
639 ext.ext_dtype().clone(),
640 ext.storage_array()
641 .clone()
642 .execute::<CanonicalValidity>(ctx)?
643 .0
644 .into_array(),
645 ),
646 ))),
647 Canonical::Variant(variant) => {
648 let core_storage = recursively_canonicalize_slots(variant.core_storage(), ctx)?;
649 let shredded = variant
650 .shredded()
651 .map(|shredded| {
652 if shredded.is::<Variant>() {
653 recursively_canonicalize_slots(shredded, ctx)
654 } else {
655 shredded
656 .clone()
657 .execute::<CanonicalValidity>(ctx)
658 .map(|canonical| canonical.0.into_array())
659 }
660 })
661 .transpose()?;
662 Ok(CanonicalValidity(Canonical::Variant(
663 VariantArray::try_new(core_storage, shredded)?,
664 )))
665 }
666 }
667 }
668}
669
670pub struct RecursiveCanonical(pub Canonical);
675
676fn recursively_canonicalize_slots(
679 array: &ArrayRef,
680 ctx: &mut ExecutionCtx,
681) -> VortexResult<ArrayRef> {
682 let slots = array
683 .slots()
684 .iter()
685 .map(|slot| {
686 slot.as_ref()
687 .map(|child| {
688 child
689 .clone()
690 .execute::<RecursiveCanonical>(ctx)
691 .map(|canonical| canonical.0.into_array())
692 })
693 .transpose()
694 })
695 .collect::<VortexResult<ArraySlots>>()?;
696 unsafe { array.clone().with_slots(slots) }
699}
700impl Executable for RecursiveCanonical {
701 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
702 match array.execute::<Canonical>(ctx)? {
703 n @ Canonical::Null(_) => Ok(RecursiveCanonical(n)),
704 Canonical::Bool(b) => {
705 let validity = child_to_validity(b.slots()[0].as_ref(), b.dtype().nullability());
706 let len = b.len();
707 let BoolDataParts { bits, meta } = b.into_data().into_parts(len);
708 Ok(RecursiveCanonical(Canonical::Bool(
709 BoolArray::try_new_from_handle(
710 bits,
711 meta.offset(),
712 meta.len(),
713 validity.execute(ctx)?,
714 )?,
715 )))
716 }
717 Canonical::Primitive(p) => {
718 let PrimitiveDataParts {
719 ptype,
720 buffer,
721 validity,
722 } = p.into_data_parts();
723 Ok(RecursiveCanonical(Canonical::Primitive(unsafe {
724 PrimitiveArray::new_unchecked_from_handle(buffer, ptype, validity.execute(ctx)?)
725 })))
726 }
727 Canonical::Decimal(d) => {
728 let DecimalDataParts {
729 decimal_dtype,
730 values,
731 values_type,
732 validity,
733 } = d.into_data_parts();
734 Ok(RecursiveCanonical(Canonical::Decimal(unsafe {
735 DecimalArray::new_unchecked_handle(
736 values,
737 values_type,
738 decimal_dtype,
739 validity.execute(ctx)?,
740 )
741 })))
742 }
743 Canonical::VarBinView(vbv) => {
744 let VarBinViewDataParts {
745 dtype,
746 buffers,
747 views,
748 validity,
749 } = vbv.into_data_parts();
750 Ok(RecursiveCanonical(Canonical::VarBinView(unsafe {
751 VarBinViewArray::new_handle_unchecked(
752 views,
753 buffers,
754 dtype,
755 validity.execute(ctx)?,
756 )
757 })))
758 }
759 Canonical::List(l) => {
760 let zctl = l.is_zero_copy_to_list();
761 let ListViewDataParts {
762 elements,
763 offsets,
764 sizes,
765 validity,
766 ..
767 } = l.into_data_parts();
768 Ok(RecursiveCanonical(Canonical::List(unsafe {
769 ListViewArray::new_unchecked(
770 elements.execute::<RecursiveCanonical>(ctx)?.0.into_array(),
771 offsets.execute::<RecursiveCanonical>(ctx)?.0.into_array(),
772 sizes.execute::<RecursiveCanonical>(ctx)?.0.into_array(),
773 validity.execute(ctx)?,
774 )
775 .with_zero_copy_to_list(zctl)
776 })))
777 }
778 Canonical::Map(map) => {
779 let map_dtype = map.map_dtype().clone();
780 let entries = map.entries().clone();
781 Ok(RecursiveCanonical(Canonical::Map(MapArray::new(
782 map_dtype,
783 entries
784 .execute::<RecursiveCanonical>(ctx)?
785 .0
786 .into_listview(),
787 ))))
788 }
789 Canonical::FixedSizeList(fsl) => {
790 let list_size = fsl.list_size();
791 let len = fsl.len();
792 let parts = fsl.into_data_parts();
793 let elements = parts.elements;
794 let validity = parts.validity;
795 Ok(RecursiveCanonical(Canonical::FixedSizeList(
796 FixedSizeListArray::new(
797 elements.execute::<RecursiveCanonical>(ctx)?.0.into_array(),
798 list_size,
799 validity.execute(ctx)?,
800 len,
801 ),
802 )))
803 }
804 Canonical::Struct(st) => {
805 let len = st.len();
806 let StructDataParts {
807 struct_fields,
808 fields,
809 validity,
810 } = st.into_data_parts();
811 let executed_fields = fields
812 .into_iter()
813 .map(|f| Ok(f.execute::<RecursiveCanonical>(ctx)?.0.into_array()))
814 .collect::<VortexResult<Vec<_>>>()?;
815
816 Ok(RecursiveCanonical(Canonical::Struct(unsafe {
817 StructArray::new_unchecked(
818 executed_fields,
819 struct_fields,
820 len,
821 validity.execute(ctx)?,
822 )
823 })))
824 }
825 Canonical::Union(union) => {
826 let UnionDataParts {
827 variants,
828 type_ids,
829 children,
830 } = union.into_data_parts();
831 let type_ids = type_ids.execute::<RecursiveCanonical>(ctx)?.0.into_array();
832 let children = children
833 .iter()
834 .cloned()
835 .map(|child| {
836 child
837 .execute::<RecursiveCanonical>(ctx)
838 .map(|canonical| canonical.0.into_array())
839 })
840 .collect::<VortexResult<Vec<_>>>()?;
841
842 Ok(RecursiveCanonical(Canonical::Union(unsafe {
843 UnionArray::new_unchecked(type_ids, variants, children)
844 })))
845 }
846 Canonical::Extension(ext) => Ok(RecursiveCanonical(Canonical::Extension(
847 ExtensionArray::new(
848 ext.ext_dtype().clone(),
849 ext.storage_array()
850 .clone()
851 .execute::<RecursiveCanonical>(ctx)?
852 .0
853 .into_array(),
854 ),
855 ))),
856 Canonical::Variant(variant) => {
857 let core_storage = recursively_canonicalize_slots(variant.core_storage(), ctx)?;
858 let shredded = variant
859 .shredded()
860 .map(|shredded| {
861 if shredded.is::<Variant>() {
862 recursively_canonicalize_slots(shredded, ctx)
863 } else {
864 shredded
865 .clone()
866 .execute::<RecursiveCanonical>(ctx)
867 .map(|canonical| canonical.0.into_array())
868 }
869 })
870 .transpose()?;
871 Ok(RecursiveCanonical(Canonical::Variant(
872 VariantArray::try_new(core_storage, shredded)?,
873 )))
874 }
875 }
876 }
877}
878
879impl<T: NativePType> Executable for Buffer<T> {
885 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
886 let array = PrimitiveArray::execute(array, ctx)?;
887 vortex_ensure!(
888 matches!(
889 array.validity()?,
890 Validity::NonNullable | Validity::AllValid
891 ),
892 "Cannot execute to native buffer: array is not all-valid."
893 );
894 Ok(array.into_buffer())
895 }
896}
897
898impl Executable for PrimitiveArray {
902 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
903 match array.try_downcast::<Primitive>() {
904 Ok(primitive) => Ok(primitive),
905 Err(array) => Ok(Canonical::execute(array, ctx)?.into_primitive()),
906 }
907 }
908}
909
910impl Executable for BoolArray {
914 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
915 match array.try_downcast::<Bool>() {
916 Ok(bool_array) => Ok(bool_array),
917 Err(array) => Ok(Canonical::execute(array, ctx)?.into_bool()),
918 }
919 }
920}
921
922impl Executable for BitBuffer {
926 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
927 let bool = BoolArray::execute(array, ctx)?;
928 assert!(
929 !bool.dtype().is_nullable(),
930 "bit buffer execute only works with non-nullable bool arrays"
931 );
932 Ok(bool.into_bit_buffer())
933 }
934}
935
936impl Executable for NullArray {
940 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
941 match array.try_downcast::<Null>() {
942 Ok(null_array) => Ok(null_array),
943 Err(array) => Ok(Canonical::execute(array, ctx)?.into_null()),
944 }
945 }
946}
947
948impl Executable for VarBinViewArray {
952 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
953 match array.try_downcast::<VarBinView>() {
954 Ok(varbinview) => Ok(varbinview),
955 Err(array) => Ok(Canonical::execute(array, ctx)?.into_varbinview()),
956 }
957 }
958}
959
960impl Executable for ExtensionArray {
964 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
965 match array.try_downcast::<Extension>() {
966 Ok(ext_array) => Ok(ext_array),
967 Err(array) => Ok(Canonical::execute(array, ctx)?.into_extension()),
968 }
969 }
970}
971
972impl Executable for DecimalArray {
976 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
977 match array.try_downcast::<Decimal>() {
978 Ok(decimal) => Ok(decimal),
979 Err(array) => Ok(Canonical::execute(array, ctx)?.into_decimal()),
980 }
981 }
982}
983
984impl Executable for ListViewArray {
988 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
989 match array.try_downcast::<ListView>() {
990 Ok(list) => Ok(list),
991 Err(array) => Ok(Canonical::execute(array, ctx)?.into_listview()),
992 }
993 }
994}
995
996impl Executable for MapArray {
1000 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1001 match array.try_downcast::<Map>() {
1002 Ok(map) => Ok(map),
1003 Err(array) => Ok(Canonical::execute(array, ctx)?.into_map()),
1004 }
1005 }
1006}
1007
1008impl Executable for FixedSizeListArray {
1012 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1013 match array.try_downcast::<FixedSizeList>() {
1014 Ok(fsl) => Ok(fsl),
1015 Err(array) => Ok(Canonical::execute(array, ctx)?.into_fixed_size_list()),
1016 }
1017 }
1018}
1019
1020impl Executable for StructArray {
1024 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1025 match array.try_downcast::<Struct>() {
1026 Ok(struct_array) => Ok(struct_array),
1027 Err(array) => Ok(Canonical::execute(array, ctx)?.into_struct()),
1028 }
1029 }
1030}
1031
1032impl Executable for UnionArray {
1036 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1037 match array.try_downcast::<Union>() {
1038 Ok(union_array) => Ok(union_array),
1039 Err(array) => Ok(Canonical::execute(array, ctx)?.into_union()),
1040 }
1041 }
1042}
1043
1044impl Executable for VariantArray {
1048 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1049 match array.try_downcast::<Variant>() {
1050 Ok(variant_array) => Ok(variant_array),
1051 Err(array) => match Canonical::execute(array, ctx)? {
1052 Canonical::Variant(variant_array) => Ok(variant_array),
1053 canonical => vortex_panic!("Cannot unwrap VariantArray from {:?}", canonical),
1054 },
1055 }
1056 }
1057}
1058
1059#[derive(Debug, Clone, Copy)]
1064pub enum CanonicalView<'a> {
1065 Null(ArrayView<'a, Null>),
1066 Bool(ArrayView<'a, Bool>),
1067 Primitive(ArrayView<'a, Primitive>),
1068 Decimal(ArrayView<'a, Decimal>),
1069 VarBinView(ArrayView<'a, VarBinView>),
1070 List(ArrayView<'a, ListView>),
1071 Map(ArrayView<'a, Map>),
1072 FixedSizeList(ArrayView<'a, FixedSizeList>),
1073 Struct(ArrayView<'a, Struct>),
1074 Union(ArrayView<'a, Union>),
1075 Extension(ArrayView<'a, Extension>),
1076 Variant(ArrayView<'a, Variant>),
1077}
1078
1079impl From<CanonicalView<'_>> for Canonical {
1080 fn from(value: CanonicalView<'_>) -> Self {
1081 match value {
1082 CanonicalView::Null(a) => Canonical::Null(a.into_owned()),
1083 CanonicalView::Bool(a) => Canonical::Bool(a.into_owned()),
1084 CanonicalView::Primitive(a) => Canonical::Primitive(a.into_owned()),
1085 CanonicalView::Decimal(a) => Canonical::Decimal(a.into_owned()),
1086 CanonicalView::VarBinView(a) => Canonical::VarBinView(a.into_owned()),
1087 CanonicalView::List(a) => Canonical::List(a.into_owned()),
1088 CanonicalView::Map(a) => Canonical::Map(a.into_owned()),
1089 CanonicalView::FixedSizeList(a) => Canonical::FixedSizeList(a.into_owned()),
1090 CanonicalView::Struct(a) => Canonical::Struct(a.into_owned()),
1091 CanonicalView::Union(a) => Canonical::Union(a.into_owned()),
1092 CanonicalView::Extension(a) => Canonical::Extension(a.into_owned()),
1093 CanonicalView::Variant(a) => Canonical::Variant(a.into_owned()),
1094 }
1095 }
1096}
1097
1098impl CanonicalView<'_> {
1099 pub fn to_array_ref(&self) -> ArrayRef {
1101 match self {
1102 CanonicalView::Null(a) => a.array().clone(),
1103 CanonicalView::Bool(a) => a.array().clone(),
1104 CanonicalView::Primitive(a) => a.array().clone(),
1105 CanonicalView::Decimal(a) => a.array().clone(),
1106 CanonicalView::VarBinView(a) => a.array().clone(),
1107 CanonicalView::List(a) => a.array().clone(),
1108 CanonicalView::Map(a) => a.array().clone(),
1109 CanonicalView::FixedSizeList(a) => a.array().clone(),
1110 CanonicalView::Struct(a) => a.array().clone(),
1111 CanonicalView::Union(a) => a.array().clone(),
1112 CanonicalView::Extension(a) => a.array().clone(),
1113 CanonicalView::Variant(a) => a.array().clone(),
1114 }
1115 }
1116}
1117
1118macro_rules! canonical_kinds {
1120 ($($kind:ident => $vtable:ty),+ $(,)?) => {
1121 #[derive(Clone, Copy)]
1123 pub(crate) enum CanonicalKind {
1124 $($kind),+
1125 }
1126
1127 impl CanonicalKind {
1128 #[inline]
1130 pub(crate) fn of<V: VTable>() -> Option<Self> {
1131 $(if TypeId::of::<V>() == TypeId::of::<$vtable>() {
1132 return Some(Self::$kind);
1133 })+
1134 None
1135 }
1136
1137 #[inline]
1140 unsafe fn view(self, array: &ArrayRef) -> CanonicalView<'_> {
1141 match self {
1142 $(Self::$kind => CanonicalView::$kind(unsafe {
1144 array.as_typed_unchecked::<$vtable>()
1145 })),+
1146 }
1147 }
1148 }
1149 };
1150}
1151
1152canonical_kinds! {
1153 Null => Null,
1154 Bool => Bool,
1155 Primitive => Primitive,
1156 Decimal => Decimal,
1157 Struct => Struct,
1158 Union => Union,
1159 List => ListView,
1160 Map => Map,
1161 FixedSizeList => FixedSizeList,
1162 VarBinView => VarBinView,
1163 Variant => Variant,
1164 Extension => Extension,
1165}
1166
1167pub struct AnyCanonical;
1169impl Matcher for AnyCanonical {
1170 type Match<'a> = CanonicalView<'a>;
1171
1172 #[inline]
1173 fn matches(array: &ArrayRef) -> bool {
1174 array.dyn_array().canonical_kind().is_some()
1175 }
1176
1177 #[inline]
1178 fn try_match(array: &ArrayRef) -> Option<Self::Match<'_>> {
1179 let kind = array.dyn_array().canonical_kind()?;
1180 Some(unsafe { kind.view(array) })
1182 }
1183}
1184
1185#[cfg(test)]
1186mod tests {
1187 use std::sync::Arc;
1188 use std::sync::LazyLock;
1189
1190 use rstest::rstest;
1191 use vortex_error::VortexResult;
1192 use vortex_error::vortex_err;
1193 use vortex_session::VortexSession;
1194
1195 use crate::ArrayRef;
1196 use crate::Canonical;
1197 use crate::CanonicalValidity;
1198 use crate::IntoArray;
1199 use crate::VortexSessionExecute;
1200 use crate::array::new_foreign_array;
1201 use crate::arrays::Constant;
1202 use crate::arrays::ConstantArray;
1203 use crate::arrays::Primitive;
1204 use crate::arrays::PrimitiveArray;
1205 use crate::arrays::Struct;
1206 use crate::arrays::VarBinArray;
1207 use crate::arrays::Variant;
1208 use crate::arrays::VariantArray;
1209 use crate::arrays::struct_::StructArrayExt;
1210 use crate::arrays::variant::VariantArraySlotsExt;
1211 use crate::assert_arrays_eq;
1212 use crate::canonical::AnyCanonical;
1213 use crate::canonical::StructArray;
1214 use crate::dtype::DType;
1215 use crate::dtype::DecimalDType;
1216 use crate::dtype::MapDType;
1217 use crate::dtype::Nullability;
1218 use crate::dtype::PType;
1219 use crate::dtype::StructFields;
1220 use crate::dtype::UnionVariants;
1221 use crate::extension::datetime::TimeUnit;
1222 use crate::extension::datetime::Timestamp;
1223 use crate::scalar::Scalar;
1224
1225 static SESSION: LazyLock<VortexSession> = LazyLock::new(crate::array_session);
1227
1228 fn variant_core_storage(len: usize) -> ArrayRef {
1229 ConstantArray::new(
1230 Scalar::variant(Scalar::primitive(1i32, Nullability::NonNullable)),
1231 len,
1232 )
1233 .into_array()
1234 }
1235
1236 fn canonical_arrays(nullability: Nullability) -> VortexResult<Vec<ArrayRef>> {
1237 let i32_dtype = DType::Primitive(PType::I32, nullability);
1238 let dtypes = [
1239 DType::Null,
1240 DType::Bool(nullability),
1241 i32_dtype.clone(),
1242 DType::Decimal(DecimalDType::try_new(10, 2)?, nullability),
1243 DType::Utf8(nullability),
1244 DType::Binary(nullability),
1245 DType::List(Arc::new(i32_dtype.clone()), nullability),
1246 DType::FixedSizeList(Arc::new(i32_dtype.clone()), 2, nullability),
1247 DType::Map(
1248 MapDType::try_new(
1249 DType::Utf8(Nullability::NonNullable),
1250 i32_dtype.clone(),
1251 false,
1252 )?,
1253 nullability,
1254 ),
1255 DType::Struct(
1256 StructFields::from_iter([("a", i32_dtype.clone())]),
1257 nullability,
1258 ),
1259 DType::Union(
1260 UnionVariants::new(["a"].into(), vec![i32_dtype])?,
1261 nullability,
1262 ),
1263 DType::Extension(Timestamp::new(TimeUnit::Microseconds, nullability).erased()),
1264 ];
1265 let mut arrays: Vec<_> = dtypes
1266 .iter()
1267 .map(|dtype| Canonical::empty(dtype).into_array())
1268 .collect();
1269 let value = Scalar::variant(Scalar::primitive(1i32, nullability))
1270 .cast(&DType::Variant(nullability))?;
1271 arrays.push(
1272 VariantArray::try_new(ConstantArray::new(value, 2).into_array(), None)?.into_array(),
1273 );
1274 Ok(arrays)
1275 }
1276
1277 #[rstest]
1278 fn any_canonical_matches_all_encodings(
1279 #[values(Nullability::NonNullable, Nullability::Nullable)] nullability: Nullability,
1280 ) -> VortexResult<()> {
1281 for array in canonical_arrays(nullability)? {
1282 assert!(array.is::<AnyCanonical>(), "{array}");
1283 let canonical = Canonical::from(array.as_::<AnyCanonical>()).into_array();
1284 assert!(ArrayRef::ptr_eq(&array, &canonical));
1285 }
1286 Ok(())
1287 }
1288
1289 #[test]
1290 fn any_canonical_rejects_noncanonical_encodings() {
1291 let arrays = [
1292 ConstantArray::new(1i32, 4).into_array(),
1293 ConstantArray::new(true, 4).into_array(),
1294 ConstantArray::new("value", 4).into_array(),
1295 VarBinArray::from_iter([Some("value")], DType::Utf8(Nullability::Nullable))
1296 .into_array(),
1297 ];
1298 for array in arrays {
1299 assert!(!array.is::<AnyCanonical>(), "{array}");
1300 assert!(array.as_opt::<AnyCanonical>().is_none(), "{array}");
1301 }
1302 }
1303
1304 #[rstest]
1305 fn any_canonical_rejects_foreign_arrays_with_canonical_ids(
1306 #[values(Nullability::NonNullable, Nullability::Nullable)] nullability: Nullability,
1307 ) -> VortexResult<()> {
1308 let mut ctx = SESSION.create_execution_ctx();
1309 for canonical in canonical_arrays(nullability)? {
1310 let foreign = new_foreign_array(
1311 canonical.encoding_id(),
1312 canonical.dtype().clone(),
1313 canonical.len(),
1314 vec![],
1315 vec![],
1316 Default::default(),
1317 )?;
1318 assert!(!foreign.is::<AnyCanonical>(), "{foreign}");
1319 assert!(foreign.as_opt::<AnyCanonical>().is_none(), "{foreign}");
1320 assert!(foreign.execute::<Canonical>(&mut ctx).is_err());
1321 }
1322 Ok(())
1323 }
1324
1325 #[test]
1326 fn canonical_validity_canonicalizes_variant_shredded_physical_slots() -> VortexResult<()> {
1327 let len = 2;
1328 let nested_shredded =
1329 StructArray::try_from_iter([("value", ConstantArray::new(10i32, len).into_array())])?;
1330 let inner_variant = VariantArray::try_new(
1331 variant_core_storage(len),
1332 Some(nested_shredded.into_array()),
1333 )?;
1334 let outer_variant =
1335 VariantArray::try_new(variant_core_storage(len), Some(inner_variant.into_array()))?;
1336
1337 let mut ctx = SESSION.create_execution_ctx();
1338 let Canonical::Variant(canonical) = outer_variant
1339 .into_array()
1340 .execute::<CanonicalValidity>(&mut ctx)?
1341 .0
1342 else {
1343 return Err(vortex_err!("expected canonical variant"));
1344 };
1345
1346 let nested_variant = canonical
1347 .shredded()
1348 .and_then(|shredded| shredded.as_opt::<Variant>())
1349 .ok_or_else(|| vortex_err!("expected nested variant shredded child"))?;
1350 let nested_struct = nested_variant
1351 .shredded()
1352 .and_then(|shredded| shredded.as_opt::<Struct>())
1353 .ok_or_else(|| vortex_err!("expected nested struct shredded child"))?;
1354 let value = nested_struct.unmasked_field_by_name("value")?;
1355
1356 assert!(value.is::<Primitive>());
1357 assert!(!value.is::<Constant>());
1358 assert_arrays_eq!(value, PrimitiveArray::from_iter([10i32, 10]), &mut ctx);
1359
1360 Ok(())
1361 }
1362}