vortex_array/arrays/varbin/vtable/
mod.rs1use std::hash::Hasher;
5
6use prost::Message;
7use vortex_error::VortexExpect;
8use vortex_error::VortexResult;
9use vortex_error::vortex_bail;
10use vortex_error::vortex_ensure;
11use vortex_error::vortex_ensure_eq;
12use vortex_error::vortex_panic;
13use vortex_session::registry::CachedId;
14
15use crate::ArrayParts;
16use crate::ArrayRef;
17use crate::ExecutionCtx;
18use crate::ExecutionResult;
19use crate::IntoArray;
20use crate::VortexSessionExecute;
21use crate::array::Array;
22use crate::array::ArrayId;
23use crate::array::ArrayView;
24use crate::array::VTable;
25use crate::arrays::PrimitiveArray;
26use crate::arrays::varbin::VarBinArrayExt;
27use crate::arrays::varbin::VarBinArraySlotsExt;
28use crate::arrays::varbin::VarBinData;
29use crate::arrays::varbin::VarBinSlots;
30use crate::buffer::BufferHandle;
31use crate::builders::ArrayBuilder;
32use crate::builders::VarBinViewBuilder;
33use crate::dtype::DType;
34use crate::dtype::Nullability;
35use crate::dtype::PType;
36use crate::match_each_integer_ptype;
37use crate::match_each_varbin_builder;
38use crate::serde::ArrayChildren;
39use crate::validity::Validity;
40pub(crate) mod canonical;
41mod kernel;
42mod operations;
43mod validity;
44
45use canonical::varbin_to_canonical;
46use vortex_session::VortexSession;
47
48use crate::EqMode;
49use crate::arrays::varbin::compute::rules::PARENT_RULES;
50use crate::hash::ArrayEq;
51use crate::hash::ArrayHash;
52
53pub type VarBinArray = Array<VarBin>;
55
56pub(crate) fn initialize(session: &VortexSession) {
57 kernel::initialize(session);
58}
59
60#[derive(Clone, prost::Message)]
61pub struct VarBinMetadata {
62 #[prost(enumeration = "PType", tag = "1")]
63 pub(crate) offsets_ptype: i32,
64}
65
66impl ArrayHash for VarBinData {
67 fn array_hash<H: Hasher>(&self, state: &mut H, accuracy: EqMode) {
68 self.bytes().array_hash(state, accuracy);
69 }
70}
71
72impl ArrayEq for VarBinData {
73 fn array_eq(&self, other: &Self, accuracy: EqMode) -> bool {
74 self.bytes().array_eq(other.bytes(), accuracy)
75 }
76}
77
78impl VTable for VarBin {
79 type TypedArrayData = VarBinData;
80
81 type OperationsVTable = Self;
82 type ValidityVTable = Self;
83 fn id(&self) -> ArrayId {
84 static ID: CachedId = CachedId::new("vortex.varbin");
85 *ID
86 }
87
88 fn nbuffers(_array: ArrayView<'_, Self>) -> usize {
89 1
90 }
91
92 fn validate(
93 &self,
94 _data: &VarBinData,
95 dtype: &DType,
96 len: usize,
97 slots: &[Option<ArrayRef>],
98 ) -> VortexResult<()> {
99 vortex_ensure_eq!(slots.len(), VarBinSlots::COUNT);
100 let offsets = slots[VarBinSlots::OFFSETS]
101 .as_ref()
102 .vortex_expect("VarBinArray offsets slot");
103 vortex_ensure_eq!(
104 offsets.len().saturating_sub(1),
105 len,
106 "VarBinArray length does not match outer length",
107 );
108 vortex_ensure!(
109 matches!(dtype, DType::Binary(_) | DType::Utf8(_)),
110 "VarBinArray dtype must be binary or utf8, got {dtype}"
111 );
112 Ok(())
113 }
114
115 fn buffer(array: ArrayView<'_, Self>, idx: usize) -> BufferHandle {
116 match idx {
117 0 => array.bytes_handle().clone(),
118 _ => vortex_panic!("VarBinArray buffer index {idx} out of bounds"),
119 }
120 }
121
122 fn buffer_name(_array: ArrayView<'_, Self>, idx: usize) -> Option<String> {
123 match idx {
124 0 => Some("bytes".to_string()),
125 _ => vortex_panic!("VarBinArray buffer_name index {idx} out of bounds"),
126 }
127 }
128
129 fn with_buffers(
130 &self,
131 array: ArrayView<'_, Self>,
132 buffers: &[BufferHandle],
133 ) -> VortexResult<ArrayParts<Self>> {
134 vortex_ensure_eq!(buffers.len(), 1);
135 let mut data = array.data().clone();
136 data.bytes = buffers[0].clone();
137 Ok(ArrayParts::new(
138 self.clone(),
139 array.dtype().clone(),
140 array.len(),
141 data,
142 array.slots().iter().cloned().collect(),
143 ))
144 }
145
146 fn serialize(
147 array: ArrayView<'_, Self>,
148 _session: &VortexSession,
149 ) -> VortexResult<Option<Vec<u8>>> {
150 Ok(Some(
151 VarBinMetadata {
152 offsets_ptype: PType::try_from(array.offsets().dtype())
153 .vortex_expect("Must be a valid PType") as i32,
154 }
155 .encode_to_vec(),
156 ))
157 }
158
159 fn deserialize(
160 &self,
161 dtype: &DType,
162 len: usize,
163 metadata: &[u8],
164 buffers: &[BufferHandle],
165 children: &dyn ArrayChildren,
166 session: &VortexSession,
167 ) -> VortexResult<ArrayParts<Self>> {
168 let metadata = VarBinMetadata::decode(metadata)?;
169 let validity = if children.len() == 1 {
170 Validity::from(dtype.nullability())
171 } else if children.len() == 2 {
172 let validity = children.get(1, &Validity::DTYPE, len)?;
173 Validity::Array(validity)
174 } else {
175 vortex_bail!("Expected 1 or 2 children, got {}", children.len());
176 };
177
178 let offsets = children.get(
179 0,
180 &DType::Primitive(metadata.offsets_ptype(), Nullability::NonNullable),
181 len + 1,
182 )?;
183
184 if buffers.len() != 1 {
185 vortex_bail!("Expected 1 buffer, got {}", buffers.len());
186 }
187 let bytes = buffers[0].clone().try_to_host_sync()?;
188
189 let data = VarBinData::try_build(
190 offsets.clone(),
191 bytes,
192 dtype.clone(),
193 validity.clone(),
194 &mut session.create_execution_ctx(),
195 )?;
196 let slots = VarBinData::make_slots(offsets, &validity, len);
197 Ok(ArrayParts::new(
198 self.clone(),
199 dtype.clone(),
200 len,
201 data,
202 slots,
203 ))
204 }
205
206 fn slot_name(_array: ArrayView<'_, Self>, idx: usize) -> String {
207 VarBinSlots::NAMES[idx].to_string()
208 }
209
210 fn reduce_parent(
211 array: ArrayView<'_, Self>,
212 parent: &ArrayRef,
213 child_idx: usize,
214 ) -> VortexResult<Option<ArrayRef>> {
215 PARENT_RULES.evaluate(array, parent, child_idx)
216 }
217
218 fn append_to_builder(
219 array: ArrayView<'_, Self>,
220 builder: &mut dyn ArrayBuilder,
221 ctx: &mut ExecutionCtx,
222 ) -> VortexResult<()> {
223 if let Some(result) =
224 match_each_varbin_builder!(builder, |builder| builder.append_varbin(array, ctx))
225 {
226 return result;
227 }
228
229 let Some(builder) = builder.as_any_mut().downcast_mut::<VarBinViewBuilder>() else {
232 vortex_bail!("append_to_builder for VarBin requires a variable-binary builder")
233 };
234 append_to_varbinview(array, builder, ctx)
235 }
236
237 fn execute(array: Array<Self>, ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult> {
238 Ok(ExecutionResult::done(
239 varbin_to_canonical(array.as_view(), ctx)?.into_array(),
240 ))
241 }
242}
243
244fn append_to_varbinview(
253 array: ArrayView<'_, VarBin>,
254 builder: &mut VarBinViewBuilder,
255 ctx: &mut ExecutionCtx,
256) -> VortexResult<()> {
257 let len = array.as_ref().len();
258 let validity = array.varbin_validity().execute_mask(len, ctx)?;
259
260 let parts = array.into_owned().into_data_parts();
261 let offsets = parts.offsets.execute::<PrimitiveArray>(ctx)?;
262 match_each_integer_ptype!(offsets.ptype(), |P| {
263 builder.append_buffer_with_offsets(
264 parts.bytes.unwrap_host(),
265 offsets.as_slice::<P>(),
266 &validity,
267 )
268 });
269 Ok(())
270}
271
272#[derive(Clone, Debug)]
273pub struct VarBin;