Skip to main content

vortex_array/vtable/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4//! This module contains the VTable definitions for a Vortex encoding.
5
6mod dyn_;
7mod operations;
8mod typed;
9mod validity;
10
11use std::fmt::Debug;
12use std::hash::Hasher;
13use std::ops::Deref;
14use std::sync::Arc;
15
16pub use dyn_::*;
17pub use operations::*;
18pub use typed::*;
19pub use validity::*;
20use vortex_error::VortexExpect;
21use vortex_error::VortexResult;
22use vortex_error::vortex_panic;
23use vortex_session::VortexSession;
24
25use crate::ArrayRef;
26use crate::Canonical;
27use crate::DynArray;
28use crate::ExecutionResult;
29use crate::IntoArray;
30use crate::Precision;
31use crate::arrays::ConstantArray;
32use crate::buffer::BufferHandle;
33use crate::builders::ArrayBuilder;
34use crate::dtype::DType;
35use crate::executor::ExecutionCtx;
36use crate::patches::Patches;
37use crate::serde::ArrayChildren;
38use crate::stats::StatsSetRef;
39use crate::validity::Validity;
40
41/// The array [`VTable`] encapsulates logic for an Array type within Vortex.
42///
43/// The logic is split across several "VTable" traits to enable easier code organization than
44/// simply lumping everything into a single trait.
45///
46/// From this [`VTable`] trait, we derive implementations for the sealed [`DynArray`] and [`DynVTable`]
47/// traits.
48///
49/// The functions defined in these vtable traits will typically document their pre- and
50/// post-conditions. The pre-conditions are validated inside the [`DynArray`] and [`DynVTable`]
51/// implementations so do not need to be checked in the vtable implementations (for example, index
52/// out of bounds). Post-conditions are validated after invocation of the vtable function and will
53/// panic if violated.
54pub trait VTable: 'static + Clone + Sized + Send + Sync + Debug {
55    type Array: 'static + Send + Sync + Clone + Debug + Deref<Target = dyn DynArray> + IntoArray;
56    type Metadata: Debug;
57
58    type OperationsVTable: OperationsVTable<Self>;
59    type ValidityVTable: ValidityVTable<Self>;
60
61    /// Returns the VTable from the array instance.
62    ///
63    // NOTE(ngates): this function is temporary while we migrate Arrays over to the unified vtable
64    fn vtable(array: &Self::Array) -> &Self;
65
66    /// Returns the ID of the array.
67    fn id(&self) -> ArrayId;
68
69    /// Returns the length of the array.
70    fn len(array: &Self::Array) -> usize;
71
72    /// Returns the DType of the array.
73    fn dtype(array: &Self::Array) -> &DType;
74
75    /// Returns the stats set for the array.
76    fn stats(array: &Self::Array) -> StatsSetRef<'_>;
77
78    /// Hashes the array contents.
79    fn array_hash<H: Hasher>(array: &Self::Array, state: &mut H, precision: Precision);
80
81    /// Compares two arrays of the same type for equality.
82    fn array_eq(array: &Self::Array, other: &Self::Array, precision: Precision) -> bool;
83
84    /// Returns the number of buffers in the array.
85    fn nbuffers(array: &Self::Array) -> usize;
86
87    /// Returns the buffer at the given index.
88    ///
89    /// # Panics
90    /// Panics if `idx >= nbuffers(array)`.
91    fn buffer(array: &Self::Array, idx: usize) -> BufferHandle;
92
93    /// Returns the name of the buffer at the given index, or `None` if unnamed.
94    fn buffer_name(array: &Self::Array, idx: usize) -> Option<String>;
95
96    /// Returns the number of children in the array.
97    fn nchildren(array: &Self::Array) -> usize;
98
99    /// Returns the child at the given index.
100    ///
101    /// # Panics
102    /// Panics if `idx >= nchildren(array)`.
103    fn child(array: &Self::Array, idx: usize) -> ArrayRef;
104
105    /// Returns the name of the child at the given index.
106    ///
107    /// # Panics
108    /// Panics if `idx >= nchildren(array)`.
109    fn child_name(array: &Self::Array, idx: usize) -> String;
110
111    /// Exports metadata for an array.
112    fn metadata(array: &Self::Array) -> VortexResult<Self::Metadata>;
113
114    /// Serialize metadata into a byte buffer for IPC or file storage.
115    /// Return `None` if the array cannot be serialized.
116    fn serialize(metadata: Self::Metadata) -> VortexResult<Option<Vec<u8>>>;
117
118    /// Deserialize array metadata from a byte buffer.
119    fn deserialize(
120        bytes: &[u8],
121        _dtype: &DType,
122        _len: usize,
123        _buffers: &[BufferHandle],
124        _session: &VortexSession,
125    ) -> VortexResult<Self::Metadata>;
126
127    /// Writes the array into a canonical builder.
128    fn append_to_builder(
129        array: &Self::Array,
130        builder: &mut dyn ArrayBuilder,
131        ctx: &mut ExecutionCtx,
132    ) -> VortexResult<()> {
133        let canonical = array.to_array().execute::<Canonical>(ctx)?.into_array();
134        builder.extend_from_array(&canonical);
135        Ok(())
136    }
137
138    /// Build an array from components.
139    fn build(
140        dtype: &DType,
141        len: usize,
142        metadata: &Self::Metadata,
143        buffers: &[BufferHandle],
144        children: &dyn ArrayChildren,
145    ) -> VortexResult<Self::Array>;
146
147    /// Replaces the children in `array` with `children`.
148    fn with_children(array: &mut Self::Array, children: Vec<ArrayRef>) -> VortexResult<()>;
149
150    /// Execute this array by returning an [`ExecutionResult`].
151    fn execute(array: Arc<Array<Self>>, ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult>;
152
153    /// Attempt to execute the parent of this array.
154    fn execute_parent(
155        array: &Array<Self>,
156        parent: &ArrayRef,
157        child_idx: usize,
158        ctx: &mut ExecutionCtx,
159    ) -> VortexResult<Option<ArrayRef>> {
160        _ = (array, parent, child_idx, ctx);
161        Ok(None)
162    }
163
164    /// Attempt to reduce the array to a simpler representation.
165    fn reduce(array: &Array<Self>) -> VortexResult<Option<ArrayRef>> {
166        _ = array;
167        Ok(None)
168    }
169
170    /// Attempt to perform a reduction of the parent of this array.
171    fn reduce_parent(
172        array: &Array<Self>,
173        parent: &ArrayRef,
174        child_idx: usize,
175    ) -> VortexResult<Option<ArrayRef>> {
176        _ = (array, parent, child_idx);
177        Ok(None)
178    }
179}
180
181/// Alias for migration — downstream code can start using `ArrayVTable`.
182pub use VTable as ArrayVTable;
183
184/// Placeholder type used to indicate when a particular vtable is not supported by the encoding.
185pub struct NotSupported;
186
187/// Returns the validity as a child array if it produces one.
188#[inline]
189pub fn validity_to_child(validity: &Validity, len: usize) -> Option<ArrayRef> {
190    match validity {
191        Validity::NonNullable | Validity::AllValid => None,
192        Validity::AllInvalid => Some(ConstantArray::new(false, len).into_array()),
193        Validity::Array(array) => Some(array.clone()),
194    }
195}
196
197/// Returns 1 if validity produces a child, 0 otherwise.
198#[inline]
199pub fn validity_nchildren(validity: &Validity) -> usize {
200    match validity {
201        Validity::NonNullable | Validity::AllValid => 0,
202        Validity::AllInvalid | Validity::Array(_) => 1,
203    }
204}
205
206/// Returns the number of children produced by patches.
207#[inline]
208pub fn patches_nchildren(patches: &Patches) -> usize {
209    2 + patches.chunk_offsets().is_some() as usize
210}
211
212/// Returns the child at the given index within a patches component.
213#[inline]
214pub fn patches_child(patches: &Patches, idx: usize) -> ArrayRef {
215    match idx {
216        0 => patches.indices().clone(),
217        1 => patches.values().clone(),
218        2 => patches
219            .chunk_offsets()
220            .as_ref()
221            .vortex_expect("patch_chunk_offsets child out of bounds")
222            .clone(),
223        _ => vortex_panic!("patches child index {idx} out of bounds"),
224    }
225}
226
227/// Returns the name of the child at the given index within a patches component.
228#[inline]
229pub fn patches_child_name(idx: usize) -> &'static str {
230    match idx {
231        0 => "patch_indices",
232        1 => "patch_values",
233        2 => "patch_chunk_offsets",
234        _ => vortex_panic!("patches child name index {idx} out of bounds"),
235    }
236}
237
238/// vtable! macro — generates IntoArray, From, Deref, AsRef for inner array types.
239///
240/// During the migration, IntoArray creates [`Array<V>`] (the new typed wrapper) while
241/// Deref/AsRef go through AlsoArrayAdapter for backward-compatible DynArray access.
242#[macro_export]
243macro_rules! vtable {
244    ($V:ident) => {
245        $crate::vtable!($V, $V);
246    };
247    ($Base:ident, $VT:ident) => {
248        $crate::aliases::paste::paste! {
249            impl AsRef<dyn $crate::DynArray> for [<$Base Array>] {
250                fn as_ref(&self) -> &dyn $crate::DynArray {
251                    // We can unsafe cast ourselves to an ArrayAdapter.
252                    unsafe { &*(self as *const [<$Base Array>] as *const $crate::ArrayAdapter<$VT>) }
253                }
254            }
255
256            impl std::ops::Deref for [<$Base Array>] {
257                type Target = dyn $crate::DynArray;
258
259                fn deref(&self) -> &Self::Target {
260                    // We can unsafe cast ourselves to an ArrayAdapter.
261                    unsafe { &*(self as *const [<$Base Array>] as *const $crate::ArrayAdapter<$VT>) }
262                }
263            }
264
265            impl $crate::IntoArray for [<$Base Array>] {
266                fn into_array(self) -> $crate::ArrayRef {
267                    use $crate::vtable::VTable;
268                    let vtable = $VT::vtable(&self).clone();
269                    let dtype = $VT::dtype(&self).clone();
270                    let len = $VT::len(&self);
271                    let stats = $VT::stats(&self).to_array_stats();
272                    // SAFETY: dtype and len are extracted from `self` via VTable methods.
273                    std::sync::Arc::new(unsafe {
274                        $crate::vtable::Array::new_unchecked(vtable, dtype, len, self, stats)
275                    })
276                }
277            }
278
279            impl From<[<$Base Array>]> for $crate::ArrayRef {
280                fn from(value: [<$Base Array>]) -> $crate::ArrayRef {
281                    use $crate::IntoArray;
282                    value.into_array()
283                }
284            }
285
286            impl [<$Base Array>] {
287                #[deprecated(note = "use `.into_array()` (owned) or `.clone().into_array()` (ref) to make clones explicit")]
288                pub fn to_array(&self) -> $crate::ArrayRef {
289                    use $crate::IntoArray;
290                    self.clone().into_array()
291                }
292            }
293        }
294    };
295}