Skip to main content

vortex_array/array/
visitor.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::fmt::Formatter;
5use std::sync::Arc;
6
7use vortex_buffer::ByteBuffer;
8use vortex_error::VortexResult;
9
10use crate::Array;
11use crate::ArrayRef;
12use crate::IntoArray;
13use crate::arrays::ConstantArray;
14use crate::buffer::BufferHandle;
15use crate::patches::Patches;
16use crate::validity::Validity;
17
18pub trait ArrayVisitor {
19    /// Returns the children of the array.
20    fn children(&self) -> Vec<ArrayRef>;
21
22    /// Returns the number of children of the array.
23    fn nchildren(&self) -> usize;
24
25    /// Returns the nth child of the array without allocating a Vec.
26    ///
27    /// Returns `None` if the index is out of bounds.
28    fn nth_child(&self, idx: usize) -> Option<ArrayRef>;
29
30    /// Returns the names of the children of the array.
31    fn children_names(&self) -> Vec<String>;
32
33    /// Returns the array's children with their names.
34    fn named_children(&self) -> Vec<(String, ArrayRef)>;
35
36    /// Returns the buffers of the array.
37    fn buffers(&self) -> Vec<ByteBuffer>;
38
39    /// Returns the buffer handles of the array.
40    fn buffer_handles(&self) -> Vec<BufferHandle>;
41
42    /// Returns the names of the buffers of the array.
43    fn buffer_names(&self) -> Vec<String>;
44
45    /// Returns the array's buffers with their names.
46    fn named_buffers(&self) -> Vec<(String, BufferHandle)>;
47
48    /// Returns the number of buffers of the array.
49    fn nbuffers(&self) -> usize;
50
51    /// Returns the serialized metadata of the array, or `None` if the array does not
52    /// support serialization.
53    fn metadata(&self) -> VortexResult<Option<Vec<u8>>>;
54
55    /// Formats a human-readable metadata description.
56    fn metadata_fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result;
57
58    /// Checks if all buffers in the array tree are host-resident.
59    ///
60    /// This will fail if any buffers of self or child arrays are GPU-resident.
61    fn is_host(&self) -> bool;
62}
63
64impl ArrayVisitor for Arc<dyn Array> {
65    fn children(&self) -> Vec<ArrayRef> {
66        self.as_ref().children()
67    }
68
69    fn nchildren(&self) -> usize {
70        self.as_ref().nchildren()
71    }
72
73    fn nth_child(&self, idx: usize) -> Option<ArrayRef> {
74        self.as_ref().nth_child(idx)
75    }
76
77    fn children_names(&self) -> Vec<String> {
78        self.as_ref().children_names()
79    }
80
81    fn named_children(&self) -> Vec<(String, ArrayRef)> {
82        self.as_ref().named_children()
83    }
84
85    fn buffers(&self) -> Vec<ByteBuffer> {
86        self.as_ref().buffers()
87    }
88
89    fn buffer_handles(&self) -> Vec<BufferHandle> {
90        self.as_ref().buffer_handles()
91    }
92
93    fn buffer_names(&self) -> Vec<String> {
94        self.as_ref().buffer_names()
95    }
96
97    fn named_buffers(&self) -> Vec<(String, BufferHandle)> {
98        self.as_ref().named_buffers()
99    }
100
101    fn nbuffers(&self) -> usize {
102        self.as_ref().nbuffers()
103    }
104
105    fn metadata(&self) -> VortexResult<Option<Vec<u8>>> {
106        self.as_ref().metadata()
107    }
108
109    fn metadata_fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
110        self.as_ref().metadata_fmt(f)
111    }
112
113    fn is_host(&self) -> bool {
114        self.as_ref().is_host()
115    }
116}
117
118pub trait ArrayVisitorExt: Array {
119    /// Count the number of buffers encoded by self and all child arrays.
120    fn nbuffers_recursive(&self) -> usize {
121        self.children()
122            .iter()
123            .map(ArrayVisitorExt::nbuffers_recursive)
124            .sum::<usize>()
125            + self.nbuffers()
126    }
127
128    /// Depth-first traversal of the array and its children.
129    fn depth_first_traversal(&self) -> impl Iterator<Item = ArrayRef> {
130        /// A depth-first pre-order iterator over an Array.
131        struct ArrayChildrenIterator {
132            stack: Vec<ArrayRef>,
133        }
134
135        impl Iterator for ArrayChildrenIterator {
136            type Item = ArrayRef;
137
138            fn next(&mut self) -> Option<Self::Item> {
139                let next = self.stack.pop()?;
140                for child in next.children().into_iter().rev() {
141                    self.stack.push(child);
142                }
143                Some(next)
144            }
145        }
146
147        ArrayChildrenIterator {
148            stack: vec![self.to_array()],
149        }
150    }
151}
152
153impl<A: Array + ?Sized> ArrayVisitorExt for A {}
154
155pub trait ArrayBufferVisitor {
156    fn visit_buffer_handle(&mut self, _name: &str, handle: &BufferHandle);
157}
158
159/// A visitor for array children that does not require names.
160///
161/// This is more efficient than [`ArrayChildVisitor`] when you only need to
162/// iterate over children without accessing their names (e.g., for counting
163/// or accessing by index).
164pub trait ArrayChildVisitorUnnamed {
165    /// Visit a child of this array.
166    fn visit_child(&mut self, array: &ArrayRef);
167
168    /// Utility for visiting Array validity.
169    fn visit_validity(&mut self, validity: &Validity, len: usize) {
170        if let Some(vlen) = validity.maybe_len() {
171            assert_eq!(vlen, len, "Validity length mismatch");
172        }
173
174        match validity {
175            Validity::NonNullable | Validity::AllValid => {}
176            Validity::AllInvalid => self.visit_child(&ConstantArray::new(false, len).into_array()),
177            Validity::Array(array) => {
178                self.visit_child(array);
179            }
180        }
181    }
182
183    /// Utility for visiting Array patches.
184    fn visit_patches(&mut self, patches: &Patches) {
185        self.visit_child(patches.indices());
186        self.visit_child(patches.values());
187        if let Some(chunk_offsets) = patches.chunk_offsets() {
188            self.visit_child(chunk_offsets);
189        }
190    }
191}
192
193pub trait ArrayChildVisitor {
194    /// Visit a child of this array.
195    fn visit_child(&mut self, _name: &str, _array: &ArrayRef);
196
197    /// Utility for visiting Array validity.
198    fn visit_validity(&mut self, validity: &Validity, len: usize) {
199        if let Some(vlen) = validity.maybe_len() {
200            assert_eq!(vlen, len, "Validity length mismatch");
201        }
202
203        match validity {
204            Validity::NonNullable | Validity::AllValid => {}
205            Validity::AllInvalid => {
206                // To avoid storing metadata about validity, we store all invalid as a
207                // constant array of false values.
208                // This gives:
209                //  * is_nullable & has_validity => Validity::Array (or Validity::AllInvalid)
210                //  * is_nullable & !has_validity => Validity::AllValid
211                //  * !is_nullable => Validity::NonNullable
212                self.visit_child("validity", &ConstantArray::new(false, len).into_array())
213            }
214            Validity::Array(array) => {
215                self.visit_child("validity", array);
216            }
217        }
218    }
219
220    /// Utility for visiting Array patches.
221    fn visit_patches(&mut self, patches: &Patches) {
222        self.visit_child("patch_indices", patches.indices());
223        self.visit_child("patch_values", patches.values());
224        if let Some(chunk_offsets) = patches.chunk_offsets() {
225            self.visit_child("patch_chunk_offsets", chunk_offsets);
226        }
227    }
228}