Skip to main content

vortex_array/array/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4mod visitor;
5
6use std::any::Any;
7use std::fmt::Debug;
8use std::fmt::Formatter;
9use std::hash::Hash;
10use std::hash::Hasher;
11use std::ops::Deref;
12use std::ops::Range;
13use std::sync::Arc;
14
15pub use visitor::*;
16use vortex_buffer::ByteBuffer;
17use vortex_dtype::DType;
18use vortex_dtype::Nullability;
19use vortex_error::VortexExpect;
20use vortex_error::VortexResult;
21use vortex_error::vortex_ensure;
22use vortex_error::vortex_err;
23use vortex_error::vortex_panic;
24use vortex_mask::Mask;
25
26use crate::AnyCanonical;
27use crate::ArrayEq;
28use crate::ArrayHash;
29use crate::Canonical;
30use crate::DynArrayEq;
31use crate::DynArrayHash;
32use crate::ExecutionCtx;
33use crate::LEGACY_SESSION;
34use crate::VortexSessionExecute;
35use crate::arrays::BoolVTable;
36use crate::arrays::ConstantVTable;
37use crate::arrays::DictArray;
38use crate::arrays::FilterArray;
39use crate::arrays::NullVTable;
40use crate::arrays::PrimitiveVTable;
41use crate::arrays::ScalarFnVTable;
42use crate::arrays::SliceArray;
43use crate::arrays::VarBinVTable;
44use crate::arrays::VarBinViewVTable;
45use crate::buffer::BufferHandle;
46use crate::builders::ArrayBuilder;
47use crate::compute;
48use crate::expr::ReduceNode;
49use crate::expr::ReduceNodeRef;
50use crate::expr::ScalarFn;
51use crate::expr::stats::Precision;
52use crate::expr::stats::Stat;
53use crate::expr::stats::StatsProviderExt;
54use crate::hash;
55use crate::matcher::Matcher;
56use crate::optimizer::ArrayOptimizer;
57use crate::scalar::Scalar;
58use crate::stats::StatsSetRef;
59use crate::validity::Validity;
60use crate::vtable::ArrayId;
61use crate::vtable::ArrayVTableExt;
62use crate::vtable::BaseArrayVTable;
63use crate::vtable::DynVTable;
64use crate::vtable::OperationsVTable;
65use crate::vtable::VTable;
66use crate::vtable::ValidityVTable;
67use crate::vtable::VisitorVTable;
68
69/// The public API trait for all Vortex arrays.
70pub trait Array:
71    'static
72    + private::Sealed
73    + Send
74    + Sync
75    + Debug
76    + DynArrayEq
77    + DynArrayHash
78    + ArrayVisitor
79    + ReduceNode
80{
81    /// Returns the array as a reference to a generic [`Any`] trait object.
82    fn as_any(&self) -> &dyn Any;
83
84    /// Returns the array as an `Arc<dyn Any + Send + Sync>`.
85    fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
86
87    /// Returns the array as an [`ArrayRef`].
88    fn to_array(&self) -> ArrayRef;
89
90    /// Returns the length of the array.
91    fn len(&self) -> usize;
92
93    /// Returns whether the array is empty (has zero rows).
94    fn is_empty(&self) -> bool {
95        self.len() == 0
96    }
97
98    /// Returns the logical Vortex [`DType`] of the array.
99    fn dtype(&self) -> &DType;
100
101    /// Returns the vtable of the array.
102    fn vtable(&self) -> &dyn DynVTable;
103
104    /// Returns the encoding ID of the array.
105    fn encoding_id(&self) -> ArrayId;
106
107    /// Performs a constant-time slice of the array.
108    fn slice(&self, range: Range<usize>) -> VortexResult<ArrayRef>;
109
110    /// Wraps the array in a [`FilterArray`] such that it is logically filtered by the given mask.
111    fn filter(&self, mask: Mask) -> VortexResult<ArrayRef>;
112
113    /// Wraps the array in a [`DictArray`] such that it is logically taken by the given indices.
114    fn take(&self, indices: ArrayRef) -> VortexResult<ArrayRef>;
115
116    /// Fetch the scalar at the given index.
117    ///
118    /// This method panics if the index is out of bounds for the array.
119    fn scalar_at(&self, index: usize) -> VortexResult<Scalar>;
120
121    /// Returns whether the item at `index` is valid.
122    fn is_valid(&self, index: usize) -> VortexResult<bool>;
123
124    /// Returns whether the item at `index` is invalid.
125    fn is_invalid(&self, index: usize) -> VortexResult<bool>;
126
127    /// Returns whether all items in the array are valid.
128    ///
129    /// This is usually cheaper than computing a precise `valid_count`, but may return false
130    /// negatives.
131    fn all_valid(&self) -> VortexResult<bool>;
132
133    /// Returns whether the array is all invalid.
134    ///
135    /// This is usually cheaper than computing a precise `invalid_count`, but may return false
136    /// negatives.
137    fn all_invalid(&self) -> VortexResult<bool>;
138
139    /// Returns the number of valid elements in the array.
140    fn valid_count(&self) -> VortexResult<usize>;
141
142    /// Returns the number of invalid elements in the array.
143    fn invalid_count(&self) -> VortexResult<usize>;
144
145    /// Returns the [`Validity`] of the array.
146    fn validity(&self) -> VortexResult<Validity>;
147
148    /// Returns the canonical validity mask for the array.
149    fn validity_mask(&self) -> VortexResult<Mask>;
150
151    /// Returns the canonical representation of the array.
152    fn to_canonical(&self) -> VortexResult<Canonical>;
153
154    /// Writes the array into the canonical builder.
155    ///
156    /// The [`DType`] of the builder must match that of the array.
157    fn append_to_builder(
158        &self,
159        builder: &mut dyn ArrayBuilder,
160        ctx: &mut ExecutionCtx,
161    ) -> VortexResult<()>;
162
163    /// Returns the statistics of the array.
164    // TODO(ngates): change how this works. It's weird.
165    fn statistics(&self) -> StatsSetRef<'_>;
166
167    /// Replaces the children of the array with the given array references.
168    fn with_children(&self, children: Vec<ArrayRef>) -> VortexResult<ArrayRef>;
169}
170
171impl Array for Arc<dyn Array> {
172    #[inline]
173    fn as_any(&self) -> &dyn Any {
174        Array::as_any(self.as_ref())
175    }
176
177    fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
178        self
179    }
180
181    #[inline]
182    fn to_array(&self) -> ArrayRef {
183        self.clone()
184    }
185
186    #[inline]
187    fn len(&self) -> usize {
188        self.as_ref().len()
189    }
190
191    #[inline]
192    fn dtype(&self) -> &DType {
193        self.as_ref().dtype()
194    }
195
196    fn vtable(&self) -> &dyn DynVTable {
197        self.as_ref().vtable()
198    }
199
200    #[inline]
201    fn encoding_id(&self) -> ArrayId {
202        self.as_ref().encoding_id()
203    }
204
205    #[inline]
206    fn slice(&self, range: Range<usize>) -> VortexResult<ArrayRef> {
207        self.as_ref().slice(range)
208    }
209
210    fn filter(&self, mask: Mask) -> VortexResult<ArrayRef> {
211        self.as_ref().filter(mask)
212    }
213
214    fn take(&self, indices: ArrayRef) -> VortexResult<ArrayRef> {
215        self.as_ref().take(indices)
216    }
217
218    #[inline]
219    fn scalar_at(&self, index: usize) -> VortexResult<Scalar> {
220        self.as_ref().scalar_at(index)
221    }
222
223    #[inline]
224    fn is_valid(&self, index: usize) -> VortexResult<bool> {
225        self.as_ref().is_valid(index)
226    }
227
228    #[inline]
229    fn is_invalid(&self, index: usize) -> VortexResult<bool> {
230        self.as_ref().is_invalid(index)
231    }
232
233    #[inline]
234    fn all_valid(&self) -> VortexResult<bool> {
235        self.as_ref().all_valid()
236    }
237
238    #[inline]
239    fn all_invalid(&self) -> VortexResult<bool> {
240        self.as_ref().all_invalid()
241    }
242
243    #[inline]
244    fn valid_count(&self) -> VortexResult<usize> {
245        self.as_ref().valid_count()
246    }
247
248    #[inline]
249    fn invalid_count(&self) -> VortexResult<usize> {
250        self.as_ref().invalid_count()
251    }
252
253    #[inline]
254    fn validity(&self) -> VortexResult<Validity> {
255        self.as_ref().validity()
256    }
257
258    #[inline]
259    fn validity_mask(&self) -> VortexResult<Mask> {
260        self.as_ref().validity_mask()
261    }
262
263    fn to_canonical(&self) -> VortexResult<Canonical> {
264        self.as_ref().to_canonical()
265    }
266
267    fn append_to_builder(
268        &self,
269        builder: &mut dyn ArrayBuilder,
270        ctx: &mut ExecutionCtx,
271    ) -> VortexResult<()> {
272        self.as_ref().append_to_builder(builder, ctx)
273    }
274
275    fn statistics(&self) -> StatsSetRef<'_> {
276        self.as_ref().statistics()
277    }
278
279    fn with_children(&self, children: Vec<ArrayRef>) -> VortexResult<ArrayRef> {
280        self.as_ref().with_children(children)
281    }
282}
283
284/// A reference counted pointer to a dynamic [`Array`] trait object.
285pub type ArrayRef = Arc<dyn Array>;
286
287impl ToOwned for dyn Array {
288    type Owned = ArrayRef;
289
290    fn to_owned(&self) -> Self::Owned {
291        self.to_array()
292    }
293}
294
295impl dyn Array + '_ {
296    /// Does the array match the given matcher.
297    pub fn is<M: Matcher>(&self) -> bool {
298        M::matches(self)
299    }
300
301    /// Returns the array downcast by the given matcher.
302    pub fn as_<M: Matcher>(&self) -> M::Match<'_> {
303        self.as_opt::<M>().vortex_expect("Failed to downcast")
304    }
305
306    /// Returns the array downcast by the given matcher.
307    pub fn as_opt<M: Matcher>(&self) -> Option<M::Match<'_>> {
308        M::try_match(self)
309    }
310
311    /// Returns the array downcast to the given `A` as an owned object.
312    pub fn try_into<V: VTable>(self: Arc<Self>) -> Result<V::Array, Arc<Self>> {
313        match self.is::<V>() {
314            true => {
315                let arc = self
316                    .as_any_arc()
317                    .downcast::<ArrayAdapter<V>>()
318                    .map_err(|_| vortex_err!("failed to downcast"))
319                    .vortex_expect("Failed to downcast");
320                Ok(match Arc::try_unwrap(arc) {
321                    Ok(array) => array.0,
322                    Err(arc) => arc.deref().0.clone(),
323                })
324            }
325            false => Err(self),
326        }
327    }
328
329    pub fn as_constant(&self) -> Option<Scalar> {
330        self.as_opt::<ConstantVTable>().map(|a| a.scalar().clone())
331    }
332
333    /// Total size of the array in bytes, including all children and buffers.
334    pub fn nbytes(&self) -> u64 {
335        let mut nbytes = 0;
336        for array in self.depth_first_traversal() {
337            for buffer in array.buffers() {
338                nbytes += buffer.len() as u64;
339            }
340        }
341        nbytes
342    }
343
344    /// Returns whether this array is an arrow encoding.
345    pub fn is_arrow(&self) -> bool {
346        self.is::<NullVTable>()
347            || self.is::<BoolVTable>()
348            || self.is::<PrimitiveVTable>()
349            || self.is::<VarBinVTable>()
350            || self.is::<VarBinViewVTable>()
351    }
352
353    /// Whether the array is of a canonical encoding.
354    pub fn is_canonical(&self) -> bool {
355        self.is::<AnyCanonical>()
356    }
357}
358
359/// Trait for converting a type into a Vortex [`ArrayRef`].
360pub trait IntoArray {
361    fn into_array(self) -> ArrayRef;
362}
363
364impl IntoArray for ArrayRef {
365    fn into_array(self) -> ArrayRef {
366        self
367    }
368}
369
370mod private {
371    use super::*;
372
373    pub trait Sealed {}
374
375    impl<V: VTable> Sealed for ArrayAdapter<V> {}
376    impl Sealed for Arc<dyn Array> {}
377}
378
379/// Adapter struct used to lift the [`VTable`] trait into an object-safe [`Array`]
380/// implementation.
381///
382/// Since this is a unit struct with `repr(transparent)`, we are able to turn un-adapted array
383/// structs into [`dyn Array`] using some cheeky casting inside [`std::ops::Deref`] and
384/// [`AsRef`]. See the `vtable!` macro for more details.
385#[repr(transparent)]
386pub struct ArrayAdapter<V: VTable>(V::Array);
387
388impl<V: VTable> ArrayAdapter<V> {
389    /// Provide a reference to the underlying array held within the adapter.
390    pub fn as_inner(&self) -> &V::Array {
391        &self.0
392    }
393}
394
395impl<V: VTable> Debug for ArrayAdapter<V> {
396    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
397        self.0.fmt(f)
398    }
399}
400
401impl<V: VTable> ReduceNode for ArrayAdapter<V> {
402    fn as_any(&self) -> &dyn Any {
403        self
404    }
405
406    fn node_dtype(&self) -> VortexResult<DType> {
407        Ok(<V::ArrayVTable as BaseArrayVTable<V>>::dtype(&self.0).clone())
408    }
409
410    fn scalar_fn(&self) -> Option<&ScalarFn> {
411        self.0.as_opt::<ScalarFnVTable>().map(|a| a.scalar_fn())
412    }
413
414    fn child(&self, idx: usize) -> ReduceNodeRef {
415        self.nth_child(idx)
416            .unwrap_or_else(|| vortex_panic!("Child index out of bounds: {}", idx))
417    }
418
419    fn child_count(&self) -> usize {
420        self.nchildren()
421    }
422}
423
424impl<V: VTable> Array for ArrayAdapter<V> {
425    fn as_any(&self) -> &dyn Any {
426        self
427    }
428
429    fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
430        self
431    }
432
433    fn to_array(&self) -> ArrayRef {
434        Arc::new(ArrayAdapter::<V>(self.0.clone()))
435    }
436
437    fn len(&self) -> usize {
438        <V::ArrayVTable as BaseArrayVTable<V>>::len(&self.0)
439    }
440
441    fn dtype(&self) -> &DType {
442        <V::ArrayVTable as BaseArrayVTable<V>>::dtype(&self.0)
443    }
444
445    fn vtable(&self) -> &dyn DynVTable {
446        V::vtable()
447    }
448
449    fn encoding_id(&self) -> ArrayId {
450        V::id(&self.0)
451    }
452
453    fn slice(&self, range: Range<usize>) -> VortexResult<ArrayRef> {
454        let start = range.start;
455        let stop = range.end;
456
457        if start == 0 && stop == self.len() {
458            return Ok(self.to_array());
459        }
460
461        vortex_ensure!(
462            start <= self.len(),
463            "OutOfBounds: start {start} > length {}",
464            self.len()
465        );
466        vortex_ensure!(
467            stop <= self.len(),
468            "OutOfBounds: stop {stop} > length {}",
469            self.len()
470        );
471
472        vortex_ensure!(start <= stop, "start ({start}) must be <= stop ({stop})");
473
474        if start == stop {
475            return Ok(Canonical::empty(self.dtype()).into_array());
476        }
477
478        let sliced = SliceArray::try_new(self.to_array(), range)?
479            .into_array()
480            .optimize()?;
481
482        // Propagate some stats from the original array to the sliced array.
483        if !sliced.is::<ConstantVTable>() {
484            self.statistics().with_iter(|iter| {
485                sliced.statistics().inherit(iter.filter(|(stat, value)| {
486                    matches!(
487                        stat,
488                        Stat::IsConstant | Stat::IsSorted | Stat::IsStrictSorted
489                    ) && value.as_ref().as_exact().is_some_and(|v| {
490                        Scalar::try_new(DType::Bool(Nullability::NonNullable), Some(v.clone()))
491                            .vortex_expect("A stat that was expected to be a boolean stat was not")
492                            .as_bool()
493                            .value()
494                            .unwrap_or_default()
495                    })
496                }));
497            });
498        }
499
500        Ok(sliced)
501    }
502
503    fn filter(&self, mask: Mask) -> VortexResult<ArrayRef> {
504        FilterArray::try_new(self.to_array(), mask)?
505            .into_array()
506            .optimize()
507    }
508
509    fn take(&self, indices: ArrayRef) -> VortexResult<ArrayRef> {
510        DictArray::try_new(indices, self.to_array())?
511            .into_array()
512            .optimize()
513    }
514
515    fn scalar_at(&self, index: usize) -> VortexResult<Scalar> {
516        vortex_ensure!(index < self.len(), OutOfBounds: index, 0, self.len());
517        if self.is_invalid(index)? {
518            return Ok(Scalar::null(self.dtype().clone()));
519        }
520        let scalar = <V::OperationsVTable as OperationsVTable<V>>::scalar_at(&self.0, index)?;
521        vortex_ensure!(self.dtype() == scalar.dtype(), "Scalar dtype mismatch");
522        Ok(scalar)
523    }
524
525    fn is_valid(&self, index: usize) -> VortexResult<bool> {
526        vortex_ensure!(index < self.len(), OutOfBounds: index, 0, self.len());
527        match self.validity()? {
528            Validity::NonNullable | Validity::AllValid => Ok(true),
529            Validity::AllInvalid => Ok(false),
530            Validity::Array(a) => a
531                .scalar_at(index)?
532                .as_bool()
533                .value()
534                .ok_or_else(|| vortex_err!("validity value at index {} is null", index)),
535        }
536    }
537
538    fn is_invalid(&self, index: usize) -> VortexResult<bool> {
539        Ok(!self.is_valid(index)?)
540    }
541
542    fn all_valid(&self) -> VortexResult<bool> {
543        match self.validity()? {
544            Validity::NonNullable | Validity::AllValid => Ok(true),
545            Validity::AllInvalid => Ok(false),
546            Validity::Array(a) => Ok(a.statistics().compute_min::<bool>().unwrap_or(false)),
547        }
548    }
549
550    fn all_invalid(&self) -> VortexResult<bool> {
551        match self.validity()? {
552            Validity::NonNullable | Validity::AllValid => Ok(false),
553            Validity::AllInvalid => Ok(true),
554            Validity::Array(a) => Ok(!a.statistics().compute_max::<bool>().unwrap_or(true)),
555        }
556    }
557
558    fn valid_count(&self) -> VortexResult<usize> {
559        if let Some(Precision::Exact(invalid_count)) =
560            self.statistics().get_as::<usize>(Stat::NullCount)
561        {
562            return Ok(self.len() - invalid_count);
563        }
564
565        let count = match self.validity()? {
566            Validity::NonNullable | Validity::AllValid => self.len(),
567            Validity::AllInvalid => 0,
568            Validity::Array(a) => {
569                let sum = compute::sum(&a)?;
570                sum.as_primitive()
571                    .as_::<usize>()
572                    .ok_or_else(|| vortex_err!("sum of validity array is null"))?
573            }
574        };
575        vortex_ensure!(count <= self.len(), "Valid count exceeds array length");
576
577        self.statistics()
578            .set(Stat::NullCount, Precision::exact(self.len() - count));
579
580        Ok(count)
581    }
582
583    fn invalid_count(&self) -> VortexResult<usize> {
584        Ok(self.len() - self.valid_count()?)
585    }
586
587    fn validity(&self) -> VortexResult<Validity> {
588        if self.dtype().is_nullable() {
589            let validity = <V::ValidityVTable as ValidityVTable<V>>::validity(&self.0)?;
590            if let Validity::Array(array) = &validity {
591                vortex_ensure!(array.len() == self.len(), "Validity array length mismatch");
592                vortex_ensure!(
593                    matches!(array.dtype(), DType::Bool(Nullability::NonNullable)),
594                    "Validity array is not non-nullable boolean: {}",
595                    self.encoding_id(),
596                );
597            }
598            Ok(validity)
599        } else {
600            Ok(Validity::NonNullable)
601        }
602    }
603
604    fn validity_mask(&self) -> VortexResult<Mask> {
605        match self.validity()? {
606            Validity::NonNullable | Validity::AllValid => Ok(Mask::new_true(self.len())),
607            Validity::AllInvalid => Ok(Mask::new_false(self.len())),
608            Validity::Array(a) => a.try_to_mask_fill_null_false(),
609        }
610    }
611
612    fn to_canonical(&self) -> VortexResult<Canonical> {
613        self.to_array()
614            .execute(&mut LEGACY_SESSION.create_execution_ctx())
615    }
616
617    fn append_to_builder(
618        &self,
619        builder: &mut dyn ArrayBuilder,
620        ctx: &mut ExecutionCtx,
621    ) -> VortexResult<()> {
622        if builder.dtype() != self.dtype() {
623            vortex_panic!(
624                "Builder dtype mismatch: expected {}, got {}",
625                self.dtype(),
626                builder.dtype(),
627            );
628        }
629        let len = builder.len();
630
631        V::append_to_builder(&self.0, builder, ctx)?;
632
633        assert_eq!(
634            len + self.len(),
635            builder.len(),
636            "Builder length mismatch after writing array for encoding {}",
637            self.encoding_id(),
638        );
639        Ok(())
640    }
641
642    fn statistics(&self) -> StatsSetRef<'_> {
643        <V::ArrayVTable as BaseArrayVTable<V>>::stats(&self.0)
644    }
645
646    fn with_children(&self, children: Vec<ArrayRef>) -> VortexResult<ArrayRef> {
647        let mut this = self.0.clone();
648        V::with_children(&mut this, children)?;
649        Ok(this.into_array())
650    }
651}
652
653impl<V: VTable> ArrayHash for ArrayAdapter<V> {
654    fn array_hash<H: Hasher>(&self, state: &mut H, precision: hash::Precision) {
655        self.0.encoding_id().hash(state);
656        <V::ArrayVTable as BaseArrayVTable<V>>::array_hash(&self.0, state, precision);
657    }
658}
659
660impl<V: VTable> ArrayEq for ArrayAdapter<V> {
661    fn array_eq(&self, other: &Self, precision: hash::Precision) -> bool {
662        <V::ArrayVTable as BaseArrayVTable<V>>::array_eq(&self.0, &other.0, precision)
663    }
664}
665
666impl<V: VTable> ArrayVisitor for ArrayAdapter<V> {
667    fn children(&self) -> Vec<ArrayRef> {
668        struct ChildrenCollector {
669            children: Vec<ArrayRef>,
670        }
671
672        impl ArrayChildVisitorUnnamed for ChildrenCollector {
673            fn visit_child(&mut self, array: &ArrayRef) {
674                self.children.push(array.clone());
675            }
676        }
677
678        let mut collector = ChildrenCollector {
679            children: Vec::new(),
680        };
681        <V::VisitorVTable as VisitorVTable<V>>::visit_children_unnamed(&self.0, &mut collector);
682        collector.children
683    }
684
685    fn nchildren(&self) -> usize {
686        <V::VisitorVTable as VisitorVTable<V>>::nchildren(&self.0)
687    }
688
689    fn nth_child(&self, idx: usize) -> Option<ArrayRef> {
690        <V::VisitorVTable as VisitorVTable<V>>::nth_child(&self.0, idx)
691    }
692
693    fn children_names(&self) -> Vec<String> {
694        struct ChildNameCollector {
695            names: Vec<String>,
696        }
697
698        impl ArrayChildVisitor for ChildNameCollector {
699            fn visit_child(&mut self, name: &str, _array: &ArrayRef) {
700                self.names.push(name.to_string());
701            }
702        }
703
704        let mut collector = ChildNameCollector { names: Vec::new() };
705        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
706        collector.names
707    }
708
709    fn named_children(&self) -> Vec<(String, ArrayRef)> {
710        struct NamedChildrenCollector {
711            children: Vec<(String, ArrayRef)>,
712        }
713
714        impl ArrayChildVisitor for NamedChildrenCollector {
715            fn visit_child(&mut self, name: &str, array: &ArrayRef) {
716                self.children.push((name.to_string(), array.to_array()));
717            }
718        }
719
720        let mut collector = NamedChildrenCollector {
721            children: Vec::new(),
722        };
723
724        <V::VisitorVTable as VisitorVTable<V>>::visit_children(&self.0, &mut collector);
725        collector.children
726    }
727
728    fn buffers(&self) -> Vec<ByteBuffer> {
729        struct BufferCollector {
730            buffers: Vec<ByteBuffer>,
731        }
732
733        impl ArrayBufferVisitor for BufferCollector {
734            fn visit_buffer_handle(&mut self, _name: &str, handle: &BufferHandle) {
735                self.buffers.push(handle.to_host_sync());
736            }
737        }
738
739        let mut collector = BufferCollector {
740            buffers: Vec::new(),
741        };
742        <V::VisitorVTable as VisitorVTable<V>>::visit_buffers(&self.0, &mut collector);
743        collector.buffers
744    }
745
746    fn buffer_handles(&self) -> Vec<BufferHandle> {
747        struct BufferHandleCollector {
748            handles: Vec<BufferHandle>,
749        }
750
751        impl ArrayBufferVisitor for BufferHandleCollector {
752            fn visit_buffer_handle(&mut self, _name: &str, handle: &BufferHandle) {
753                self.handles.push(handle.clone());
754            }
755        }
756
757        let mut collector = BufferHandleCollector {
758            handles: Vec::new(),
759        };
760        <V::VisitorVTable as VisitorVTable<V>>::visit_buffers(&self.0, &mut collector);
761        collector.handles
762    }
763
764    fn buffer_names(&self) -> Vec<String> {
765        <V::VisitorVTable as VisitorVTable<V>>::buffer_names(&self.0)
766    }
767
768    fn named_buffers(&self) -> Vec<(String, BufferHandle)> {
769        struct NamedBufferCollector {
770            buffers: Vec<(String, BufferHandle)>,
771        }
772
773        impl ArrayBufferVisitor for NamedBufferCollector {
774            fn visit_buffer_handle(&mut self, name: &str, handle: &BufferHandle) {
775                self.buffers.push((name.to_string(), handle.clone()));
776            }
777        }
778
779        let mut collector = NamedBufferCollector {
780            buffers: Vec::new(),
781        };
782        <V::VisitorVTable as VisitorVTable<V>>::visit_buffers(&self.0, &mut collector);
783        collector.buffers
784    }
785
786    fn nbuffers(&self) -> usize {
787        <V::VisitorVTable as VisitorVTable<V>>::nbuffers(&self.0)
788    }
789
790    fn metadata(&self) -> VortexResult<Option<Vec<u8>>> {
791        V::serialize(V::metadata(&self.0)?)
792    }
793
794    fn metadata_fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
795        match V::metadata(&self.0) {
796            Err(e) => write!(f, "<serde error: {e}>"),
797            Ok(metadata) => Debug::fmt(&metadata, f),
798        }
799    }
800
801    fn is_host(&self) -> bool {
802        for array in self.depth_first_traversal() {
803            if !array.buffer_handles().iter().all(BufferHandle::is_on_host) {
804                return false;
805            }
806        }
807
808        true
809    }
810}
811
812/// Implement a matcher for a specific VTable type
813impl<V: VTable> Matcher for V {
814    type Match<'a> = &'a V::Array;
815
816    fn matches(array: &dyn Array) -> bool {
817        Array::as_any(array).is::<ArrayAdapter<V>>()
818    }
819
820    fn try_match<'a>(array: &'a dyn Array) -> Option<Self::Match<'a>> {
821        Array::as_any(array)
822            .downcast_ref::<ArrayAdapter<V>>()
823            .map(|array_adapter| &array_adapter.0)
824    }
825}