vortex_array/arrays/primitive/vtable/
mod.rs1use kernel::PARENT_KERNELS;
5use vortex_error::VortexExpect;
6use vortex_error::VortexResult;
7use vortex_error::vortex_bail;
8use vortex_error::vortex_ensure;
9use vortex_error::vortex_panic;
10
11use crate::ArrayRef;
12use crate::EmptyMetadata;
13use crate::ExecutionCtx;
14use crate::arrays::PrimitiveArray;
15use crate::buffer::BufferHandle;
16use crate::dtype::DType;
17use crate::dtype::PType;
18use crate::serde::ArrayChildren;
19use crate::validity::Validity;
20use crate::vtable;
21use crate::vtable::VTable;
22use crate::vtable::ValidityVTableFromValidityHelper;
23use crate::vtable::validity_nchildren;
24use crate::vtable::validity_to_child;
25mod kernel;
26mod operations;
27mod validity;
28
29use std::hash::Hash;
30use std::hash::Hasher;
31
32use vortex_buffer::Alignment;
33use vortex_session::VortexSession;
34
35use crate::Precision;
36use crate::arrays::primitive::compute::rules::RULES;
37use crate::hash::ArrayEq;
38use crate::hash::ArrayHash;
39use crate::stats::StatsSetRef;
40use crate::vtable::ArrayId;
41
42vtable!(Primitive);
43
44impl VTable for PrimitiveVTable {
45 type Array = PrimitiveArray;
46
47 type Metadata = EmptyMetadata;
48 type OperationsVTable = Self;
49 type ValidityVTable = ValidityVTableFromValidityHelper;
50
51 fn id(_array: &Self::Array) -> ArrayId {
52 Self::ID
53 }
54
55 fn len(array: &PrimitiveArray) -> usize {
56 array.buffer_handle().len() / array.ptype().byte_width()
57 }
58
59 fn dtype(array: &PrimitiveArray) -> &DType {
60 &array.dtype
61 }
62
63 fn stats(array: &PrimitiveArray) -> StatsSetRef<'_> {
64 array.stats_set.to_ref(array.as_ref())
65 }
66
67 fn array_hash<H: Hasher>(array: &PrimitiveArray, state: &mut H, precision: Precision) {
68 array.dtype.hash(state);
69 array.buffer.array_hash(state, precision);
70 array.validity.array_hash(state, precision);
71 }
72
73 fn array_eq(array: &PrimitiveArray, other: &PrimitiveArray, precision: Precision) -> bool {
74 array.dtype == other.dtype
75 && array.buffer.array_eq(&other.buffer, precision)
76 && array.validity.array_eq(&other.validity, precision)
77 }
78
79 fn nbuffers(_array: &PrimitiveArray) -> usize {
80 1
81 }
82
83 fn buffer(array: &PrimitiveArray, idx: usize) -> BufferHandle {
84 match idx {
85 0 => array.buffer_handle().clone(),
86 _ => vortex_panic!("PrimitiveArray buffer index {idx} out of bounds"),
87 }
88 }
89
90 fn buffer_name(_array: &PrimitiveArray, idx: usize) -> Option<String> {
91 match idx {
92 0 => Some("values".to_string()),
93 _ => None,
94 }
95 }
96
97 fn nchildren(array: &PrimitiveArray) -> usize {
98 validity_nchildren(&array.validity)
99 }
100
101 fn child(array: &PrimitiveArray, idx: usize) -> ArrayRef {
102 match idx {
103 0 => validity_to_child(&array.validity, array.len())
104 .vortex_expect("PrimitiveArray child index out of bounds"),
105 _ => vortex_panic!("PrimitiveArray child index {idx} out of bounds"),
106 }
107 }
108
109 fn child_name(_array: &PrimitiveArray, _idx: usize) -> String {
110 "validity".to_string()
111 }
112
113 fn metadata(_array: &PrimitiveArray) -> VortexResult<Self::Metadata> {
114 Ok(EmptyMetadata)
115 }
116
117 fn serialize(_metadata: Self::Metadata) -> VortexResult<Option<Vec<u8>>> {
118 Ok(Some(vec![]))
119 }
120
121 fn deserialize(
122 _bytes: &[u8],
123 _dtype: &DType,
124 _len: usize,
125 _buffers: &[BufferHandle],
126 _session: &VortexSession,
127 ) -> VortexResult<Self::Metadata> {
128 Ok(EmptyMetadata)
129 }
130
131 fn build(
132 dtype: &DType,
133 len: usize,
134 _metadata: &Self::Metadata,
135 buffers: &[BufferHandle],
136 children: &dyn ArrayChildren,
137 ) -> VortexResult<PrimitiveArray> {
138 if buffers.len() != 1 {
139 vortex_bail!("Expected 1 buffer, got {}", buffers.len());
140 }
141 let buffer = buffers[0].clone();
142
143 let validity = if children.is_empty() {
144 Validity::from(dtype.nullability())
145 } else if children.len() == 1 {
146 let validity = children.get(0, &Validity::DTYPE, len)?;
147 Validity::Array(validity)
148 } else {
149 vortex_bail!("Expected 0 or 1 child, got {}", children.len());
150 };
151
152 let ptype = PType::try_from(dtype)?;
153
154 vortex_ensure!(
155 buffer.is_aligned_to(Alignment::new(ptype.byte_width())),
156 "Misaligned buffer cannot be used to build PrimitiveArray of {ptype}"
157 );
158
159 if buffer.len() != ptype.byte_width() * len {
160 vortex_bail!(
161 "Buffer length {} does not match expected length {} for {}, {}",
162 buffer.len(),
163 ptype.byte_width() * len,
164 ptype.byte_width(),
165 len,
166 );
167 }
168
169 vortex_ensure!(
170 buffer.is_aligned_to(Alignment::new(ptype.byte_width())),
171 "PrimitiveArray::build: Buffer (align={}) must be aligned to {}",
172 buffer.alignment(),
173 ptype.byte_width()
174 );
175
176 unsafe {
178 Ok(PrimitiveArray::new_unchecked_from_handle(
179 buffer, ptype, validity,
180 ))
181 }
182 }
183
184 fn with_children(array: &mut Self::Array, children: Vec<ArrayRef>) -> VortexResult<()> {
185 vortex_ensure!(
186 children.len() <= 1,
187 "PrimitiveArray can have at most 1 child (validity), got {}",
188 children.len()
189 );
190
191 array.validity = if children.is_empty() {
192 Validity::from(array.dtype().nullability())
193 } else {
194 Validity::Array(children.into_iter().next().vortex_expect("checked"))
195 };
196
197 Ok(())
198 }
199
200 fn execute(array: &Self::Array, _ctx: &mut ExecutionCtx) -> VortexResult<ArrayRef> {
201 Ok(array.to_array())
202 }
203
204 fn reduce_parent(
205 array: &Self::Array,
206 parent: &ArrayRef,
207 child_idx: usize,
208 ) -> VortexResult<Option<ArrayRef>> {
209 RULES.evaluate(array, parent, child_idx)
210 }
211
212 fn execute_parent(
213 array: &Self::Array,
214 parent: &ArrayRef,
215 child_idx: usize,
216 ctx: &mut ExecutionCtx,
217 ) -> VortexResult<Option<ArrayRef>> {
218 PARENT_KERNELS.execute(array, parent, child_idx, ctx)
219 }
220}
221
222#[derive(Debug)]
223pub struct PrimitiveVTable;
224
225impl PrimitiveVTable {
226 pub const ID: ArrayId = ArrayId::new_ref("vortex.primitive");
227}