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