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