1use std::sync::Arc;
7
8use vortex_buffer::BitBuffer;
9use vortex_buffer::Buffer;
10use vortex_error::VortexExpect;
11use vortex_error::VortexResult;
12use vortex_error::vortex_ensure;
13use vortex_error::vortex_panic;
14
15use crate::ArrayRef;
16use crate::ArraySlots;
17use crate::Executable;
18use crate::ExecutionCtx;
19use crate::IntoArray;
20use crate::array::ArrayView;
21use crate::array::child_to_validity;
22use crate::arrays::Bool;
23use crate::arrays::BoolArray;
24use crate::arrays::Decimal;
25use crate::arrays::DecimalArray;
26use crate::arrays::Extension;
27use crate::arrays::ExtensionArray;
28use crate::arrays::FixedSizeList;
29use crate::arrays::FixedSizeListArray;
30use crate::arrays::ListView;
31use crate::arrays::ListViewArray;
32use crate::arrays::Null;
33use crate::arrays::NullArray;
34use crate::arrays::Primitive;
35use crate::arrays::PrimitiveArray;
36use crate::arrays::Struct;
37use crate::arrays::StructArray;
38use crate::arrays::Union;
39use crate::arrays::UnionArray;
40use crate::arrays::VarBinView;
41use crate::arrays::VarBinViewArray;
42use crate::arrays::Variant;
43use crate::arrays::VariantArray;
44use crate::arrays::bool::BoolDataParts;
45use crate::arrays::decimal::DecimalDataParts;
46use crate::arrays::extension::ExtensionArrayExt;
47use crate::arrays::fixed_size_list::FixedSizeListArrayExt;
48use crate::arrays::listview::ListViewDataParts;
49use crate::arrays::listview::ListViewRebuildMode;
50use crate::arrays::primitive::PrimitiveDataParts;
51use crate::arrays::struct_::StructDataParts;
52use crate::arrays::union::UnionDataParts;
53use crate::arrays::varbinview::VarBinViewDataParts;
54use crate::arrays::variant::VariantArraySlotsExt;
55use crate::dtype::DType;
56use crate::dtype::NativePType;
57use crate::dtype::Nullability;
58use crate::dtype::PType;
59use crate::match_each_decimal_value_type;
60use crate::match_each_native_ptype;
61use crate::matcher::Matcher;
62use crate::validity::Validity;
63
64#[derive(Debug, Clone)]
126pub enum Canonical {
127 Null(NullArray),
128 Bool(BoolArray),
129 Primitive(PrimitiveArray),
130 Decimal(DecimalArray),
131 VarBinView(VarBinViewArray),
132 List(ListViewArray),
133 FixedSizeList(FixedSizeListArray),
134 Struct(StructArray),
135 Union(UnionArray),
136 Extension(ExtensionArray),
138 Variant(VariantArray),
140}
141
142macro_rules! match_each_canonical {
144 ($self:expr, | $ident:ident | $eval:expr) => {{
145 match $self {
146 Canonical::Null($ident) => $eval,
147 Canonical::Bool($ident) => $eval,
148 Canonical::Primitive($ident) => $eval,
149 Canonical::Decimal($ident) => $eval,
150 Canonical::VarBinView($ident) => $eval,
151 Canonical::List($ident) => $eval,
152 Canonical::FixedSizeList($ident) => $eval,
153 Canonical::Struct($ident) => $eval,
154 Canonical::Union($ident) => $eval,
155 Canonical::Variant($ident) => $eval,
156 Canonical::Extension($ident) => $eval,
157 }
158 }};
159}
160
161impl Canonical {
162 pub fn empty(dtype: &DType) -> Canonical {
164 match dtype {
165 DType::Null => Canonical::Null(NullArray::new(0)),
166 DType::Bool(n) => Canonical::Bool(unsafe {
167 BoolArray::new_unchecked(BitBuffer::empty(), Validity::from(n))
168 }),
169 DType::Primitive(ptype, n) => {
170 match_each_native_ptype!(ptype, |P| {
171 Canonical::Primitive(unsafe {
172 PrimitiveArray::new_unchecked(Buffer::<P>::empty(), Validity::from(n))
173 })
174 })
175 }
176 DType::Decimal(decimal_type, n) => {
177 match_each_decimal_value_type!(
178 DecimalType::smallest_decimal_value_type(decimal_type),
179 |D| {
180 Canonical::Decimal(unsafe {
181 DecimalArray::new_unchecked::<D>(
182 Buffer::empty(),
183 *decimal_type,
184 Validity::from(n),
185 )
186 })
187 }
188 )
189 }
190 DType::Utf8(n) => Canonical::VarBinView(unsafe {
191 VarBinViewArray::new_unchecked(
192 Buffer::empty(),
193 Arc::new([]),
194 dtype.clone(),
195 Validity::from(n),
196 )
197 }),
198 DType::Binary(n) => Canonical::VarBinView(unsafe {
199 VarBinViewArray::new_unchecked(
200 Buffer::empty(),
201 Arc::new([]),
202 dtype.clone(),
203 Validity::from(n),
204 )
205 }),
206 DType::List(dtype, n) => Canonical::List(unsafe {
207 ListViewArray::new_unchecked(
208 Canonical::empty(dtype).into_array(),
209 Canonical::empty(&DType::Primitive(PType::U8, Nullability::NonNullable))
210 .into_array(),
211 Canonical::empty(&DType::Primitive(PType::U8, Nullability::NonNullable))
212 .into_array(),
213 Validity::from(n),
214 )
215 .with_zero_copy_to_list(true)
217 }),
218 DType::FixedSizeList(elem_dtype, list_size, null) => Canonical::FixedSizeList(unsafe {
219 FixedSizeListArray::new_unchecked(
220 Canonical::empty(elem_dtype).into_array(),
221 *list_size,
222 Validity::from(null),
223 0,
224 )
225 }),
226 DType::Struct(struct_dtype, n) => Canonical::Struct(unsafe {
227 StructArray::new_unchecked(
228 struct_dtype
229 .fields()
230 .map(|f| Canonical::empty(&f).into_array())
231 .collect::<Arc<[_]>>(),
232 struct_dtype.clone(),
233 0,
234 Validity::from(n),
235 )
236 }),
237 DType::Union(variants, nullability) => {
238 Canonical::Union(UnionArray::empty(variants.clone(), *nullability))
239 }
240 DType::Variant(_) => {
241 vortex_panic!(InvalidArgument: "Canonical empty is not supported for Variant")
242 }
243 DType::Extension(ext_dtype) => Canonical::Extension(ExtensionArray::new(
244 ext_dtype.clone(),
245 Canonical::empty(ext_dtype.storage_dtype()).into_array(),
246 )),
247 }
248 }
249
250 pub fn len(&self) -> usize {
251 match_each_canonical!(self, |arr| arr.len())
252 }
253
254 pub fn dtype(&self) -> &DType {
255 match_each_canonical!(self, |arr| arr.dtype())
256 }
257
258 pub fn is_empty(&self) -> bool {
259 match_each_canonical!(self, |arr| arr.is_empty())
260 }
261}
262
263impl Canonical {
264 pub fn compact(&self, ctx: &mut ExecutionCtx) -> VortexResult<Canonical> {
272 match self {
273 Canonical::VarBinView(array) => Ok(Canonical::VarBinView(array.compact_buffers(ctx)?)),
274 Canonical::List(array) => Ok(Canonical::List(
275 array.rebuild(ListViewRebuildMode::TrimElements, ctx)?,
276 )),
277 _ => Ok(self.clone()),
278 }
279 }
280}
281
282impl Canonical {
284 pub fn as_null(&self) -> &NullArray {
285 if let Canonical::Null(a) = self {
286 a
287 } else {
288 vortex_panic!("Cannot get NullArray from {:?}", &self)
289 }
290 }
291
292 pub fn into_null(self) -> NullArray {
293 if let Canonical::Null(a) = self {
294 a
295 } else {
296 vortex_panic!("Cannot unwrap NullArray from {:?}", &self)
297 }
298 }
299
300 pub fn as_bool(&self) -> &BoolArray {
301 if let Canonical::Bool(a) = self {
302 a
303 } else {
304 vortex_panic!("Cannot get BoolArray from {:?}", &self)
305 }
306 }
307
308 pub fn into_bool(self) -> BoolArray {
309 if let Canonical::Bool(a) = self {
310 a
311 } else {
312 vortex_panic!("Cannot unwrap BoolArray from {:?}", &self)
313 }
314 }
315
316 pub fn as_primitive(&self) -> &PrimitiveArray {
317 if let Canonical::Primitive(a) = self {
318 a
319 } else {
320 vortex_panic!("Cannot get PrimitiveArray from {:?}", &self)
321 }
322 }
323
324 pub fn into_primitive(self) -> PrimitiveArray {
325 if let Canonical::Primitive(a) = self {
326 a
327 } else {
328 vortex_panic!("Cannot unwrap PrimitiveArray from {:?}", &self)
329 }
330 }
331
332 pub fn as_decimal(&self) -> &DecimalArray {
333 if let Canonical::Decimal(a) = self {
334 a
335 } else {
336 vortex_panic!("Cannot get DecimalArray from {:?}", &self)
337 }
338 }
339
340 pub fn into_decimal(self) -> DecimalArray {
341 if let Canonical::Decimal(a) = self {
342 a
343 } else {
344 vortex_panic!("Cannot unwrap DecimalArray from {:?}", &self)
345 }
346 }
347
348 pub fn as_varbinview(&self) -> &VarBinViewArray {
349 if let Canonical::VarBinView(a) = self {
350 a
351 } else {
352 vortex_panic!("Cannot get VarBinViewArray from {:?}", &self)
353 }
354 }
355
356 pub fn into_varbinview(self) -> VarBinViewArray {
357 if let Canonical::VarBinView(a) = self {
358 a
359 } else {
360 vortex_panic!("Cannot unwrap VarBinViewArray from {:?}", &self)
361 }
362 }
363
364 pub fn as_listview(&self) -> &ListViewArray {
365 if let Canonical::List(a) = self {
366 a
367 } else {
368 vortex_panic!("Cannot get ListArray from {:?}", &self)
369 }
370 }
371
372 pub fn into_listview(self) -> ListViewArray {
373 if let Canonical::List(a) = self {
374 a
375 } else {
376 vortex_panic!("Cannot unwrap ListArray from {:?}", &self)
377 }
378 }
379
380 pub fn as_fixed_size_list(&self) -> &FixedSizeListArray {
381 if let Canonical::FixedSizeList(a) = self {
382 a
383 } else {
384 vortex_panic!("Cannot get FixedSizeListArray from {:?}", &self)
385 }
386 }
387
388 pub fn into_fixed_size_list(self) -> FixedSizeListArray {
389 if let Canonical::FixedSizeList(a) = self {
390 a
391 } else {
392 vortex_panic!("Cannot unwrap FixedSizeListArray from {:?}", &self)
393 }
394 }
395
396 pub fn as_struct(&self) -> &StructArray {
397 if let Canonical::Struct(a) = self {
398 a
399 } else {
400 vortex_panic!("Cannot get StructArray from {:?}", &self)
401 }
402 }
403
404 pub fn into_struct(self) -> StructArray {
405 if let Canonical::Struct(a) = self {
406 a
407 } else {
408 vortex_panic!("Cannot unwrap StructArray from {:?}", &self)
409 }
410 }
411
412 pub fn as_union(&self) -> &UnionArray {
414 if let Canonical::Union(a) = self {
415 a
416 } else {
417 vortex_panic!("Cannot get UnionArray from {:?}", &self)
418 }
419 }
420
421 pub fn into_union(self) -> UnionArray {
423 if let Canonical::Union(a) = self {
424 a
425 } else {
426 vortex_panic!("Cannot unwrap UnionArray from {:?}", &self)
427 }
428 }
429
430 pub fn as_extension(&self) -> &ExtensionArray {
431 if let Canonical::Extension(a) = self {
432 a
433 } else {
434 vortex_panic!("Cannot get ExtensionArray from {:?}", &self)
435 }
436 }
437
438 pub fn into_extension(self) -> ExtensionArray {
439 if let Canonical::Extension(a) = self {
440 a
441 } else {
442 vortex_panic!("Cannot unwrap ExtensionArray from {:?}", &self)
443 }
444 }
445}
446
447impl IntoArray for Canonical {
448 fn into_array(self) -> ArrayRef {
449 match_each_canonical!(self, |arr| arr.into_array())
450 }
451}
452
453#[deprecated(note = "use `array.execute::<T>(ctx)` instead")]
459pub trait ToCanonical {
460 #[deprecated(note = "use `array.execute::<NullArray>(ctx)` instead")]
462 fn to_null(&self) -> NullArray;
463
464 #[deprecated(note = "use `array.execute::<BoolArray>(ctx)` instead")]
466 fn to_bool(&self) -> BoolArray;
467
468 #[deprecated(note = "use `array.execute::<PrimitiveArray>(ctx)` instead")]
471 fn to_primitive(&self) -> PrimitiveArray;
472
473 #[deprecated(note = "use `array.execute::<DecimalArray>(ctx)` instead")]
476 fn to_decimal(&self) -> DecimalArray;
477
478 #[deprecated(note = "use `array.execute::<StructArray>(ctx)` instead")]
480 fn to_struct(&self) -> StructArray;
481
482 #[deprecated(note = "use `array.execute::<ListViewArray>(ctx)` instead")]
484 fn to_listview(&self) -> ListViewArray;
485
486 #[deprecated(note = "use `array.execute::<FixedSizeListArray>(ctx)` instead")]
489 fn to_fixed_size_list(&self) -> FixedSizeListArray;
490
491 #[deprecated(note = "use `array.execute::<VarBinViewArray>(ctx)` instead")]
494 fn to_varbinview(&self) -> VarBinViewArray;
495
496 #[deprecated(note = "use `array.execute::<ExtensionArray>(ctx)` instead")]
499 fn to_extension(&self) -> ExtensionArray;
500}
501
502#[expect(deprecated)]
504impl ToCanonical for ArrayRef {
505 fn to_null(&self) -> NullArray {
506 #[expect(deprecated)]
507 let result = self.to_canonical().vortex_expect("to_canonical failed");
508 result.into_null()
509 }
510
511 fn to_bool(&self) -> BoolArray {
512 #[expect(deprecated)]
513 let result = self.to_canonical().vortex_expect("to_canonical failed");
514 result.into_bool()
515 }
516
517 fn to_primitive(&self) -> PrimitiveArray {
518 #[expect(deprecated)]
519 let result = self.to_canonical().vortex_expect("to_canonical failed");
520 result.into_primitive()
521 }
522
523 fn to_decimal(&self) -> DecimalArray {
524 #[expect(deprecated)]
525 let result = self.to_canonical().vortex_expect("to_canonical failed");
526 result.into_decimal()
527 }
528
529 fn to_struct(&self) -> StructArray {
530 #[expect(deprecated)]
531 let result = self.to_canonical().vortex_expect("to_canonical failed");
532 result.into_struct()
533 }
534
535 fn to_listview(&self) -> ListViewArray {
536 #[expect(deprecated)]
537 let result = self.to_canonical().vortex_expect("to_canonical failed");
538 result.into_listview()
539 }
540
541 fn to_fixed_size_list(&self) -> FixedSizeListArray {
542 #[expect(deprecated)]
543 let result = self.to_canonical().vortex_expect("to_canonical failed");
544 result.into_fixed_size_list()
545 }
546
547 fn to_varbinview(&self) -> VarBinViewArray {
548 #[expect(deprecated)]
549 let result = self.to_canonical().vortex_expect("to_canonical failed");
550 result.into_varbinview()
551 }
552
553 fn to_extension(&self) -> ExtensionArray {
554 #[expect(deprecated)]
555 let result = self.to_canonical().vortex_expect("to_canonical failed");
556 result.into_extension()
557 }
558}
559
560impl From<Canonical> for ArrayRef {
561 fn from(value: Canonical) -> Self {
562 match_each_canonical!(value, |arr| arr.into_array())
563 }
564}
565
566impl Executable for Canonical {
572 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
573 let result = array.execute_until::<AnyCanonical>(ctx)?;
574 Ok(result
575 .as_opt::<AnyCanonical>()
576 .map(Canonical::from)
577 .vortex_expect("execute_until::<AnyCanonical> must return a canonical array"))
578 }
579}
580
581pub struct CanonicalValidity(pub Canonical);
586
587impl Executable for CanonicalValidity {
588 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
589 match array.execute::<Canonical>(ctx)? {
590 n @ Canonical::Null(_) => Ok(CanonicalValidity(n)),
591 Canonical::Bool(b) => {
592 let validity = child_to_validity(b.slots()[0].as_ref(), b.dtype().nullability());
593 let len = b.len();
594 let BoolDataParts { bits, meta } = b.into_data().into_parts(len);
595 Ok(CanonicalValidity(Canonical::Bool(
596 BoolArray::try_new_from_handle(
597 bits,
598 meta.offset(),
599 meta.len(),
600 validity.execute(ctx)?,
601 )?,
602 )))
603 }
604 Canonical::Primitive(p) => {
605 let PrimitiveDataParts {
606 ptype,
607 buffer,
608 validity,
609 } = p.into_data_parts();
610 Ok(CanonicalValidity(Canonical::Primitive(unsafe {
611 PrimitiveArray::new_unchecked_from_handle(buffer, ptype, validity.execute(ctx)?)
612 })))
613 }
614 Canonical::Decimal(d) => {
615 let DecimalDataParts {
616 decimal_dtype,
617 values,
618 values_type,
619 validity,
620 } = d.into_data_parts();
621 Ok(CanonicalValidity(Canonical::Decimal(unsafe {
622 DecimalArray::new_unchecked_handle(
623 values,
624 values_type,
625 decimal_dtype,
626 validity.execute(ctx)?,
627 )
628 })))
629 }
630 Canonical::VarBinView(vbv) => {
631 let VarBinViewDataParts {
632 dtype,
633 buffers,
634 views,
635 validity,
636 } = vbv.into_data_parts();
637 Ok(CanonicalValidity(Canonical::VarBinView(unsafe {
638 VarBinViewArray::new_handle_unchecked(
639 views,
640 buffers,
641 dtype,
642 validity.execute(ctx)?,
643 )
644 })))
645 }
646 Canonical::List(l) => {
647 let zctl = l.is_zero_copy_to_list();
648 let ListViewDataParts {
649 elements,
650 offsets,
651 sizes,
652 validity,
653 ..
654 } = l.into_data_parts();
655 Ok(CanonicalValidity(Canonical::List(unsafe {
656 ListViewArray::new_unchecked(elements, offsets, sizes, validity.execute(ctx)?)
657 .with_zero_copy_to_list(zctl)
658 })))
659 }
660 Canonical::FixedSizeList(fsl) => {
661 let list_size = fsl.list_size();
662 let len = fsl.len();
663 let parts = fsl.into_data_parts();
664 let elements = parts.elements;
665 let validity = parts.validity;
666 Ok(CanonicalValidity(Canonical::FixedSizeList(
667 FixedSizeListArray::new(elements, list_size, validity.execute(ctx)?, len),
668 )))
669 }
670 Canonical::Struct(st) => {
671 let len = st.len();
672 let StructDataParts {
673 struct_fields,
674 fields,
675 validity,
676 } = st.into_data_parts();
677 Ok(CanonicalValidity(Canonical::Struct(unsafe {
678 StructArray::new_unchecked(fields, struct_fields, len, validity.execute(ctx)?)
679 })))
680 }
681 Canonical::Union(union) => {
682 let UnionDataParts {
683 variants,
684 type_ids,
685 children,
686 } = union.into_data_parts();
687 let type_ids = type_ids.execute::<CanonicalValidity>(ctx)?.0.into_array();
688
689 Ok(CanonicalValidity(Canonical::Union(unsafe {
690 UnionArray::new_unchecked(type_ids, variants, children)
691 })))
692 }
693 Canonical::Extension(ext) => Ok(CanonicalValidity(Canonical::Extension(
694 ExtensionArray::new(
695 ext.ext_dtype().clone(),
696 ext.storage_array()
697 .clone()
698 .execute::<CanonicalValidity>(ctx)?
699 .0
700 .into_array(),
701 ),
702 ))),
703 Canonical::Variant(variant) => {
704 let core_storage = recursively_canonicalize_slots(variant.core_storage(), ctx)?;
705 let shredded = variant
706 .shredded()
707 .map(|shredded| {
708 if shredded.is::<Variant>() {
709 recursively_canonicalize_slots(shredded, ctx)
710 } else {
711 shredded
712 .clone()
713 .execute::<CanonicalValidity>(ctx)
714 .map(|canonical| canonical.0.into_array())
715 }
716 })
717 .transpose()?;
718 Ok(CanonicalValidity(Canonical::Variant(
719 VariantArray::try_new(core_storage, shredded)?,
720 )))
721 }
722 }
723 }
724}
725
726pub struct RecursiveCanonical(pub Canonical);
731
732fn recursively_canonicalize_slots(
735 array: &ArrayRef,
736 ctx: &mut ExecutionCtx,
737) -> VortexResult<ArrayRef> {
738 let slots = array
739 .slots()
740 .iter()
741 .map(|slot| {
742 slot.as_ref()
743 .map(|child| {
744 child
745 .clone()
746 .execute::<RecursiveCanonical>(ctx)
747 .map(|canonical| canonical.0.into_array())
748 })
749 .transpose()
750 })
751 .collect::<VortexResult<ArraySlots>>()?;
752 unsafe { array.clone().with_slots(slots) }
755}
756impl Executable for RecursiveCanonical {
757 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
758 match array.execute::<Canonical>(ctx)? {
759 n @ Canonical::Null(_) => Ok(RecursiveCanonical(n)),
760 Canonical::Bool(b) => {
761 let validity = child_to_validity(b.slots()[0].as_ref(), b.dtype().nullability());
762 let len = b.len();
763 let BoolDataParts { bits, meta } = b.into_data().into_parts(len);
764 Ok(RecursiveCanonical(Canonical::Bool(
765 BoolArray::try_new_from_handle(
766 bits,
767 meta.offset(),
768 meta.len(),
769 validity.execute(ctx)?,
770 )?,
771 )))
772 }
773 Canonical::Primitive(p) => {
774 let PrimitiveDataParts {
775 ptype,
776 buffer,
777 validity,
778 } = p.into_data_parts();
779 Ok(RecursiveCanonical(Canonical::Primitive(unsafe {
780 PrimitiveArray::new_unchecked_from_handle(buffer, ptype, validity.execute(ctx)?)
781 })))
782 }
783 Canonical::Decimal(d) => {
784 let DecimalDataParts {
785 decimal_dtype,
786 values,
787 values_type,
788 validity,
789 } = d.into_data_parts();
790 Ok(RecursiveCanonical(Canonical::Decimal(unsafe {
791 DecimalArray::new_unchecked_handle(
792 values,
793 values_type,
794 decimal_dtype,
795 validity.execute(ctx)?,
796 )
797 })))
798 }
799 Canonical::VarBinView(vbv) => {
800 let VarBinViewDataParts {
801 dtype,
802 buffers,
803 views,
804 validity,
805 } = vbv.into_data_parts();
806 Ok(RecursiveCanonical(Canonical::VarBinView(unsafe {
807 VarBinViewArray::new_handle_unchecked(
808 views,
809 buffers,
810 dtype,
811 validity.execute(ctx)?,
812 )
813 })))
814 }
815 Canonical::List(l) => {
816 let zctl = l.is_zero_copy_to_list();
817 let ListViewDataParts {
818 elements,
819 offsets,
820 sizes,
821 validity,
822 ..
823 } = l.into_data_parts();
824 Ok(RecursiveCanonical(Canonical::List(unsafe {
825 ListViewArray::new_unchecked(
826 elements.execute::<RecursiveCanonical>(ctx)?.0.into_array(),
827 offsets.execute::<RecursiveCanonical>(ctx)?.0.into_array(),
828 sizes.execute::<RecursiveCanonical>(ctx)?.0.into_array(),
829 validity.execute(ctx)?,
830 )
831 .with_zero_copy_to_list(zctl)
832 })))
833 }
834 Canonical::FixedSizeList(fsl) => {
835 let list_size = fsl.list_size();
836 let len = fsl.len();
837 let parts = fsl.into_data_parts();
838 let elements = parts.elements;
839 let validity = parts.validity;
840 Ok(RecursiveCanonical(Canonical::FixedSizeList(
841 FixedSizeListArray::new(
842 elements.execute::<RecursiveCanonical>(ctx)?.0.into_array(),
843 list_size,
844 validity.execute(ctx)?,
845 len,
846 ),
847 )))
848 }
849 Canonical::Struct(st) => {
850 let len = st.len();
851 let StructDataParts {
852 struct_fields,
853 fields,
854 validity,
855 } = st.into_data_parts();
856 let executed_fields = fields
857 .iter()
858 .map(|f| Ok(f.clone().execute::<RecursiveCanonical>(ctx)?.0.into_array()))
859 .collect::<VortexResult<Arc<[_]>>>()?;
860
861 Ok(RecursiveCanonical(Canonical::Struct(unsafe {
862 StructArray::new_unchecked(
863 executed_fields,
864 struct_fields,
865 len,
866 validity.execute(ctx)?,
867 )
868 })))
869 }
870 Canonical::Union(union) => {
871 let UnionDataParts {
872 variants,
873 type_ids,
874 children,
875 } = union.into_data_parts();
876 let type_ids = type_ids.execute::<RecursiveCanonical>(ctx)?.0.into_array();
877 let children = children
878 .iter()
879 .cloned()
880 .map(|child| {
881 child
882 .execute::<RecursiveCanonical>(ctx)
883 .map(|canonical| canonical.0.into_array())
884 })
885 .collect::<VortexResult<Arc<[_]>>>()?;
886
887 Ok(RecursiveCanonical(Canonical::Union(unsafe {
888 UnionArray::new_unchecked(type_ids, variants, children)
889 })))
890 }
891 Canonical::Extension(ext) => Ok(RecursiveCanonical(Canonical::Extension(
892 ExtensionArray::new(
893 ext.ext_dtype().clone(),
894 ext.storage_array()
895 .clone()
896 .execute::<RecursiveCanonical>(ctx)?
897 .0
898 .into_array(),
899 ),
900 ))),
901 Canonical::Variant(variant) => {
902 let core_storage = recursively_canonicalize_slots(variant.core_storage(), ctx)?;
903 let shredded = variant
904 .shredded()
905 .map(|shredded| {
906 if shredded.is::<Variant>() {
907 recursively_canonicalize_slots(shredded, ctx)
908 } else {
909 shredded
910 .clone()
911 .execute::<RecursiveCanonical>(ctx)
912 .map(|canonical| canonical.0.into_array())
913 }
914 })
915 .transpose()?;
916 Ok(RecursiveCanonical(Canonical::Variant(
917 VariantArray::try_new(core_storage, shredded)?,
918 )))
919 }
920 }
921 }
922}
923
924impl<T: NativePType> Executable for Buffer<T> {
930 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
931 let array = PrimitiveArray::execute(array, ctx)?;
932 vortex_ensure!(
933 matches!(
934 array.validity()?,
935 Validity::NonNullable | Validity::AllValid
936 ),
937 "Cannot execute to native buffer: array is not all-valid."
938 );
939 Ok(array.into_buffer())
940 }
941}
942
943impl Executable for PrimitiveArray {
947 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
948 match array.try_downcast::<Primitive>() {
949 Ok(primitive) => Ok(primitive),
950 Err(array) => Ok(Canonical::execute(array, ctx)?.into_primitive()),
951 }
952 }
953}
954
955impl Executable for BoolArray {
959 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
960 match array.try_downcast::<Bool>() {
961 Ok(bool_array) => Ok(bool_array),
962 Err(array) => Ok(Canonical::execute(array, ctx)?.into_bool()),
963 }
964 }
965}
966
967impl Executable for BitBuffer {
971 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
972 let bool = BoolArray::execute(array, ctx)?;
973 assert!(
974 !bool.dtype().is_nullable(),
975 "bit buffer execute only works with non-nullable bool arrays"
976 );
977 Ok(bool.into_bit_buffer())
978 }
979}
980
981impl Executable for NullArray {
985 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
986 match array.try_downcast::<Null>() {
987 Ok(null_array) => Ok(null_array),
988 Err(array) => Ok(Canonical::execute(array, ctx)?.into_null()),
989 }
990 }
991}
992
993impl Executable for VarBinViewArray {
997 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
998 match array.try_downcast::<VarBinView>() {
999 Ok(varbinview) => Ok(varbinview),
1000 Err(array) => Ok(Canonical::execute(array, ctx)?.into_varbinview()),
1001 }
1002 }
1003}
1004
1005impl Executable for ExtensionArray {
1009 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1010 match array.try_downcast::<Extension>() {
1011 Ok(ext_array) => Ok(ext_array),
1012 Err(array) => Ok(Canonical::execute(array, ctx)?.into_extension()),
1013 }
1014 }
1015}
1016
1017impl Executable for DecimalArray {
1021 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1022 match array.try_downcast::<Decimal>() {
1023 Ok(decimal) => Ok(decimal),
1024 Err(array) => Ok(Canonical::execute(array, ctx)?.into_decimal()),
1025 }
1026 }
1027}
1028
1029impl Executable for ListViewArray {
1033 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1034 match array.try_downcast::<ListView>() {
1035 Ok(list) => Ok(list),
1036 Err(array) => Ok(Canonical::execute(array, ctx)?.into_listview()),
1037 }
1038 }
1039}
1040
1041impl Executable for FixedSizeListArray {
1045 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1046 match array.try_downcast::<FixedSizeList>() {
1047 Ok(fsl) => Ok(fsl),
1048 Err(array) => Ok(Canonical::execute(array, ctx)?.into_fixed_size_list()),
1049 }
1050 }
1051}
1052
1053impl Executable for StructArray {
1057 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1058 match array.try_downcast::<Struct>() {
1059 Ok(struct_array) => Ok(struct_array),
1060 Err(array) => Ok(Canonical::execute(array, ctx)?.into_struct()),
1061 }
1062 }
1063}
1064
1065impl Executable for UnionArray {
1069 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1070 match array.try_downcast::<Union>() {
1071 Ok(union_array) => Ok(union_array),
1072 Err(array) => Ok(Canonical::execute(array, ctx)?.into_union()),
1073 }
1074 }
1075}
1076
1077impl Executable for VariantArray {
1081 fn execute(array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
1082 match array.try_downcast::<Variant>() {
1083 Ok(variant_array) => Ok(variant_array),
1084 Err(array) => match Canonical::execute(array, ctx)? {
1085 Canonical::Variant(variant_array) => Ok(variant_array),
1086 canonical => vortex_panic!("Cannot unwrap VariantArray from {:?}", canonical),
1087 },
1088 }
1089 }
1090}
1091
1092#[derive(Debug, Clone, Copy)]
1097pub enum CanonicalView<'a> {
1098 Null(ArrayView<'a, Null>),
1099 Bool(ArrayView<'a, Bool>),
1100 Primitive(ArrayView<'a, Primitive>),
1101 Decimal(ArrayView<'a, Decimal>),
1102 VarBinView(ArrayView<'a, VarBinView>),
1103 List(ArrayView<'a, ListView>),
1104 FixedSizeList(ArrayView<'a, FixedSizeList>),
1105 Struct(ArrayView<'a, Struct>),
1106 Union(ArrayView<'a, Union>),
1107 Extension(ArrayView<'a, Extension>),
1108 Variant(ArrayView<'a, Variant>),
1109}
1110
1111impl From<CanonicalView<'_>> for Canonical {
1112 fn from(value: CanonicalView<'_>) -> Self {
1113 match value {
1114 CanonicalView::Null(a) => Canonical::Null(a.into_owned()),
1115 CanonicalView::Bool(a) => Canonical::Bool(a.into_owned()),
1116 CanonicalView::Primitive(a) => Canonical::Primitive(a.into_owned()),
1117 CanonicalView::Decimal(a) => Canonical::Decimal(a.into_owned()),
1118 CanonicalView::VarBinView(a) => Canonical::VarBinView(a.into_owned()),
1119 CanonicalView::List(a) => Canonical::List(a.into_owned()),
1120 CanonicalView::FixedSizeList(a) => Canonical::FixedSizeList(a.into_owned()),
1121 CanonicalView::Struct(a) => Canonical::Struct(a.into_owned()),
1122 CanonicalView::Union(a) => Canonical::Union(a.into_owned()),
1123 CanonicalView::Extension(a) => Canonical::Extension(a.into_owned()),
1124 CanonicalView::Variant(a) => Canonical::Variant(a.into_owned()),
1125 }
1126 }
1127}
1128
1129impl CanonicalView<'_> {
1130 pub fn to_array_ref(&self) -> ArrayRef {
1132 match self {
1133 CanonicalView::Null(a) => a.array().clone(),
1134 CanonicalView::Bool(a) => a.array().clone(),
1135 CanonicalView::Primitive(a) => a.array().clone(),
1136 CanonicalView::Decimal(a) => a.array().clone(),
1137 CanonicalView::VarBinView(a) => a.array().clone(),
1138 CanonicalView::List(a) => a.array().clone(),
1139 CanonicalView::FixedSizeList(a) => a.array().clone(),
1140 CanonicalView::Struct(a) => a.array().clone(),
1141 CanonicalView::Union(a) => a.array().clone(),
1142 CanonicalView::Extension(a) => a.array().clone(),
1143 CanonicalView::Variant(a) => a.array().clone(),
1144 }
1145 }
1146}
1147
1148pub struct AnyCanonical;
1150impl Matcher for AnyCanonical {
1151 type Match<'a> = CanonicalView<'a>;
1152
1153 #[inline]
1154 fn matches(array: &ArrayRef) -> bool {
1155 array.is::<Null>()
1156 || array.is::<Bool>()
1157 || array.is::<Primitive>()
1158 || array.is::<Decimal>()
1159 || array.is::<Struct>()
1160 || array.is::<Union>()
1161 || array.is::<ListView>()
1162 || array.is::<FixedSizeList>()
1163 || array.is::<VarBinView>()
1164 || array.is::<Variant>()
1165 || array.is::<Extension>()
1166 }
1167
1168 #[inline]
1169 fn try_match(array: &ArrayRef) -> Option<Self::Match<'_>> {
1170 if let Some(a) = array.as_opt::<Null>() {
1171 Some(CanonicalView::Null(a))
1172 } else if let Some(a) = array.as_opt::<Bool>() {
1173 Some(CanonicalView::Bool(a))
1174 } else if let Some(a) = array.as_opt::<Primitive>() {
1175 Some(CanonicalView::Primitive(a))
1176 } else if let Some(a) = array.as_opt::<Decimal>() {
1177 Some(CanonicalView::Decimal(a))
1178 } else if let Some(a) = array.as_opt::<Struct>() {
1179 Some(CanonicalView::Struct(a))
1180 } else if let Some(a) = array.as_opt::<Union>() {
1181 Some(CanonicalView::Union(a))
1182 } else if let Some(a) = array.as_opt::<ListView>() {
1183 Some(CanonicalView::List(a))
1184 } else if let Some(a) = array.as_opt::<FixedSizeList>() {
1185 Some(CanonicalView::FixedSizeList(a))
1186 } else if let Some(a) = array.as_opt::<VarBinView>() {
1187 Some(CanonicalView::VarBinView(a))
1188 } else if let Some(a) = array.as_opt::<Variant>() {
1189 Some(CanonicalView::Variant(a))
1190 } else {
1191 array.as_opt::<Extension>().map(CanonicalView::Extension)
1192 }
1193 }
1194}
1195
1196#[cfg(test)]
1197mod test {
1198 use std::sync::LazyLock;
1199
1200 use vortex_error::VortexResult;
1201 use vortex_error::vortex_err;
1202 use vortex_session::VortexSession;
1203
1204 use crate::ArrayRef;
1205 use crate::Canonical;
1206 use crate::CanonicalValidity;
1207 use crate::IntoArray;
1208 use crate::VortexSessionExecute;
1209 use crate::arrays::Constant;
1210 use crate::arrays::ConstantArray;
1211 use crate::arrays::Primitive;
1212 use crate::arrays::Struct;
1213 use crate::arrays::Variant;
1214 use crate::arrays::VariantArray;
1215 use crate::arrays::struct_::StructArrayExt;
1216 use crate::arrays::variant::VariantArraySlotsExt;
1217 use crate::canonical::StructArray;
1218 use crate::dtype::Nullability;
1219 use crate::scalar::Scalar;
1220
1221 static SESSION: LazyLock<VortexSession> = LazyLock::new(crate::array_session);
1223
1224 fn variant_core_storage(len: usize) -> ArrayRef {
1225 ConstantArray::new(
1226 Scalar::variant(Scalar::primitive(1i32, Nullability::NonNullable)),
1227 len,
1228 )
1229 .into_array()
1230 }
1231
1232 #[test]
1233 fn canonical_validity_canonicalizes_variant_shredded_physical_slots() -> VortexResult<()> {
1234 let len = 2;
1235 let nested_shredded =
1236 StructArray::try_from_iter([("value", ConstantArray::new(10i32, len).into_array())])?;
1237 let inner_variant = VariantArray::try_new(
1238 variant_core_storage(len),
1239 Some(nested_shredded.into_array()),
1240 )?;
1241 let outer_variant =
1242 VariantArray::try_new(variant_core_storage(len), Some(inner_variant.into_array()))?;
1243
1244 let mut ctx = SESSION.create_execution_ctx();
1245 let Canonical::Variant(canonical) = outer_variant
1246 .into_array()
1247 .execute::<CanonicalValidity>(&mut ctx)?
1248 .0
1249 else {
1250 return Err(vortex_err!("expected canonical variant"));
1251 };
1252
1253 let nested_variant = canonical
1254 .shredded()
1255 .and_then(|shredded| shredded.as_opt::<Variant>())
1256 .ok_or_else(|| vortex_err!("expected nested variant shredded child"))?;
1257 let nested_struct = nested_variant
1258 .shredded()
1259 .and_then(|shredded| shredded.as_opt::<Struct>())
1260 .ok_or_else(|| vortex_err!("expected nested struct shredded child"))?;
1261 let value = nested_struct.unmasked_field_by_name("value")?;
1262
1263 assert!(value.is::<Primitive>());
1264 assert!(!value.is::<Constant>());
1265
1266 Ok(())
1267 }
1268}