1use std::any::Any;
5
6use itertools::Itertools;
7use vortex_error::VortexExpect;
8use vortex_error::VortexResult;
9use vortex_error::vortex_bail;
10use vortex_error::vortex_ensure;
11use vortex_error::vortex_panic;
12
13use crate::ArrayRef;
14use crate::ExecutionCtx;
15use crate::IntoArray;
16use crate::arrays::StructArray;
17use crate::arrays::struct_::StructArrayExt;
18use crate::builders::ArrayBuilder;
19use crate::builders::ChildBuilder;
20use crate::builders::DEFAULT_BUILDER_CAPACITY;
21use crate::builders::ValidityBuilder;
22use crate::canonical::Canonical;
23use crate::dtype::DType;
24use crate::dtype::Nullability;
25use crate::dtype::StructFields;
26use crate::scalar::Scalar;
27use crate::scalar::StructScalar;
28
29pub struct StructBuilder {
31 dtype: DType,
32 builders: Vec<ChildBuilder>,
33 nulls: ValidityBuilder,
34}
35
36impl StructBuilder {
37 pub fn new(struct_dtype: StructFields, nullability: Nullability) -> Self {
39 Self::with_capacity(struct_dtype, nullability, DEFAULT_BUILDER_CAPACITY)
40 }
41
42 pub fn with_capacity(
44 struct_dtype: StructFields,
45 nullability: Nullability,
46 capacity: usize,
47 ) -> Self {
48 let builders = struct_dtype
49 .fields()
50 .map(|dt| ChildBuilder::with_capacity(&dt, capacity))
51 .collect();
52
53 Self {
54 builders,
55 nulls: ValidityBuilder::new(capacity),
56 dtype: DType::Struct(struct_dtype, nullability),
57 }
58 }
59
60 pub fn append_value(&mut self, struct_scalar: StructScalar) -> VortexResult<()> {
62 if !self.dtype.is_nullable() && struct_scalar.is_null() {
63 vortex_bail!("Tried to append a null `StructScalar` to a non-nullable struct builder",);
64 }
65
66 if struct_scalar.struct_fields() != self.struct_fields() {
67 vortex_bail!(
68 "Tried to append a `StructScalar` with fields {} to a \
69 struct builder with fields {}",
70 struct_scalar.struct_fields(),
71 self.struct_fields()
72 );
73 }
74
75 if let Some(fields) = struct_scalar.fields_iter() {
76 for (builder, field) in self.builders.iter_mut().zip_eq(fields) {
77 builder.append_scalar(&field)?;
78 }
79 self.nulls.append_non_null();
80 } else {
81 self.append_null()
82 }
83
84 Ok(())
85 }
86
87 pub fn finish_into_struct(&mut self) -> StructArray {
89 let len = self.len();
90 let fields = self
91 .builders
92 .iter_mut()
93 .map(|builder| builder.finish())
94 .collect::<Vec<_>>();
95
96 if fields.len() > 1 {
97 let expected_length = fields[0].len();
98 for (index, field) in fields[1..].iter().enumerate() {
99 assert_eq!(
100 field.len(),
101 expected_length,
102 "Field {index} does not have expected length {expected_length}"
103 );
104 }
105 }
106
107 let validity = self.nulls.finish_with_nullability(self.dtype.nullability());
108
109 StructArray::try_new_with_dtype(fields, self.struct_fields().clone(), len, validity)
110 .vortex_expect("Fields must all have same length.")
111 }
112
113 pub fn struct_fields(&self) -> &StructFields {
115 let DType::Struct(struct_fields, _) = &self.dtype else {
116 vortex_panic!("`StructBuilder` somehow had dtype {}", self.dtype);
117 };
118
119 struct_fields
120 }
121
122 pub(crate) fn append_struct_array(
125 &mut self,
126 array: &StructArray,
127 ctx: &mut ExecutionCtx,
128 ) -> VortexResult<()> {
129 for (field, builder) in array
130 .iter_unmasked_fields()
131 .zip_eq(self.builders.iter_mut())
132 {
133 builder.append_array(field, ctx)?;
134 }
135
136 self.nulls.append_validity(array.validity()?, array.len());
137 Ok(())
138 }
139}
140
141impl ArrayBuilder for StructBuilder {
142 fn as_any(&self) -> &dyn Any {
143 self
144 }
145
146 fn as_any_mut(&mut self) -> &mut dyn Any {
147 self
148 }
149
150 fn dtype(&self) -> &DType {
151 &self.dtype
152 }
153
154 fn len(&self) -> usize {
155 self.nulls.len()
156 }
157
158 fn append_zeros(&mut self, n: usize) {
159 self.builders
160 .iter_mut()
161 .for_each(|builder| builder.append_zeros(n));
162 self.nulls.append_n_non_nulls(n);
163 }
164
165 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
166 self.builders
167 .iter_mut()
168 .for_each(|builder| builder.append_defaults(n));
171 self.nulls.append_n_nulls(n);
172 }
173
174 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
175 vortex_ensure!(
176 scalar.dtype() == self.dtype(),
177 "StructBuilder expected scalar with dtype {}, got {}",
178 self.dtype(),
179 scalar.dtype()
180 );
181
182 self.append_value(scalar.as_struct())
183 }
184
185 fn reserve_exact(&mut self, capacity: usize) {
186 self.builders.iter_mut().for_each(|builder| {
187 builder.reserve_exact(capacity);
188 });
189 self.nulls.reserve_exact(capacity);
190 }
191
192 fn finish(&mut self) -> ArrayRef {
193 self.finish_into_struct().into_array()
194 }
195
196 fn finish_into_canonical(&mut self, _ctx: &mut ExecutionCtx) -> Canonical {
197 Canonical::Struct(self.finish_into_struct())
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use crate::IntoArray;
204 use crate::VortexSessionExecute;
205 use crate::array_session;
206 use crate::arrays::PrimitiveArray;
207 use crate::arrays::VarBinArray;
208 use crate::assert_arrays_eq;
209 use crate::builders::ArrayBuilder;
210 use crate::builders::struct_::StructArray;
211 use crate::builders::struct_::StructBuilder;
212 use crate::dtype::DType;
213 use crate::dtype::Nullability;
214 use crate::dtype::PType::I32;
215 use crate::dtype::StructFields;
216 use crate::scalar::Scalar;
217 use crate::validity::Validity;
218
219 #[test]
220 fn test_struct_builder() {
221 let sdt = StructFields::new(["a", "b"].into(), vec![I32.into(), I32.into()]);
222 let dtype = DType::Struct(sdt.clone(), Nullability::NonNullable);
223 let mut builder = StructBuilder::with_capacity(sdt, Nullability::NonNullable, 0);
224
225 builder
226 .append_value(Scalar::struct_(dtype.clone(), vec![1.into(), 2.into()]).as_struct())
227 .unwrap();
228
229 let struct_ = builder.finish();
230 assert_eq!(struct_.len(), 1);
231 assert_eq!(struct_.dtype(), &dtype);
232 }
233
234 #[test]
235 fn test_append_nullable_struct() {
236 let sdt = StructFields::new(["a", "b"].into(), vec![I32.into(), I32.into()]);
237 let dtype = DType::Struct(sdt.clone(), Nullability::Nullable);
238 let mut builder = StructBuilder::with_capacity(sdt, Nullability::Nullable, 0);
239
240 builder
241 .append_value(Scalar::struct_(dtype.clone(), vec![1.into(), 2.into()]).as_struct())
242 .unwrap();
243
244 builder.append_nulls(2);
245
246 let struct_ = builder.finish();
247 assert_eq!(struct_.len(), 3);
248 assert_eq!(struct_.dtype(), &dtype);
249 assert_eq!(
250 struct_
251 .valid_count(&mut array_session().create_execution_ctx())
252 .unwrap(),
253 1
254 );
255 }
256
257 #[test]
258 fn test_append_scalar() {
259 let mut ctx = array_session().create_execution_ctx();
260 use crate::scalar::Scalar;
261
262 let dtype = DType::Struct(
263 StructFields::from_iter([
264 ("a", DType::Primitive(I32, Nullability::Nullable)),
265 ("b", DType::Utf8(Nullability::Nullable)),
266 ]),
267 Nullability::Nullable,
268 );
269
270 let struct_fields = match &dtype {
271 DType::Struct(fields, _) => fields.clone(),
272 _ => panic!("Expected struct dtype"),
273 };
274 let mut builder = StructBuilder::new(struct_fields, Nullability::Nullable);
275
276 let struct_scalar1 = Scalar::struct_(
278 dtype.clone(),
279 vec![
280 Scalar::primitive(42i32, Nullability::Nullable),
281 Scalar::utf8("hello", Nullability::Nullable),
282 ],
283 );
284 builder.append_scalar(&struct_scalar1).unwrap();
285
286 let struct_scalar2 = Scalar::struct_(
288 dtype.clone(),
289 vec![
290 Scalar::primitive(84i32, Nullability::Nullable),
291 Scalar::utf8("world", Nullability::Nullable),
292 ],
293 );
294 builder.append_scalar(&struct_scalar2).unwrap();
295
296 let null_scalar = Scalar::null(dtype.clone());
298 builder.append_scalar(&null_scalar).unwrap();
299
300 let array = builder.finish_into_struct();
301
302 let expected = StructArray::try_from_iter_with_validity(
303 [
304 (
305 "a",
306 PrimitiveArray::from_option_iter([Some(42i32), Some(84), Some(123)])
307 .into_array(),
308 ),
309 (
310 "b",
311 <VarBinArray as FromIterator<_>>::from_iter([
312 Some("hello"),
313 Some("world"),
314 Some("x"),
315 ])
316 .into_array(),
317 ),
318 ],
319 Validity::from_iter([true, true, false]),
320 )
321 .unwrap();
322 assert_arrays_eq!(&array, &expected, &mut ctx);
323
324 let struct_fields = match &dtype {
326 DType::Struct(fields, _) => fields.clone(),
327 _ => panic!("Expected struct dtype"),
328 };
329 let mut builder = StructBuilder::new(struct_fields, Nullability::NonNullable);
330 let wrong_scalar = Scalar::from(42i32);
331 assert!(builder.append_scalar(&wrong_scalar).is_err());
332 }
333}