vortex_array/builders/
struct_.rs1use std::any::Any;
2
3use itertools::Itertools;
4use vortex_dtype::{DType, Nullability, StructFields};
5use vortex_error::{VortexExpect, VortexResult, vortex_bail};
6use vortex_mask::Mask;
7use vortex_scalar::StructScalar;
8
9use crate::arrays::StructArray;
10use crate::builders::lazy_validity_builder::LazyNullBufferBuilder;
11use crate::builders::{ArrayBuilder, ArrayBuilderExt, builder_with_capacity};
12use crate::{Array, ArrayRef, IntoArray, ToCanonical};
13
14pub struct StructBuilder {
15 builders: Vec<Box<dyn ArrayBuilder>>,
16 validity: LazyNullBufferBuilder,
17 struct_dtype: StructFields,
18 nullability: Nullability,
19 dtype: DType,
20}
21
22impl StructBuilder {
23 pub fn with_capacity(
24 struct_dtype: StructFields,
25 nullability: Nullability,
26 capacity: usize,
27 ) -> Self {
28 let builders = struct_dtype
29 .fields()
30 .map(|dt| builder_with_capacity(&dt, capacity))
31 .collect();
32
33 Self {
34 builders,
35 validity: LazyNullBufferBuilder::new(capacity),
36 struct_dtype: struct_dtype.clone(),
37 nullability,
38 dtype: DType::Struct(struct_dtype, nullability),
39 }
40 }
41
42 pub fn append_value(&mut self, struct_scalar: StructScalar) -> VortexResult<()> {
43 if struct_scalar.dtype() != &DType::Struct(self.struct_dtype.clone(), self.nullability) {
44 vortex_bail!(
45 "Expected struct scalar with dtype {:?}, found {:?}",
46 self.struct_dtype,
47 struct_scalar.dtype()
48 )
49 }
50
51 if let Some(fields) = struct_scalar.fields() {
52 for (builder, field) in self.builders.iter_mut().zip_eq(fields) {
53 builder.append_scalar(&field)?;
54 }
55 self.validity.append_non_null();
56 } else {
57 self.append_null()
58 }
59
60 Ok(())
61 }
62}
63
64impl ArrayBuilder for StructBuilder {
65 fn as_any(&self) -> &dyn Any {
66 self
67 }
68
69 fn as_any_mut(&mut self) -> &mut dyn Any {
70 self
71 }
72
73 fn dtype(&self) -> &DType {
74 &self.dtype
75 }
76
77 fn len(&self) -> usize {
78 self.validity.len()
79 }
80
81 fn append_zeros(&mut self, n: usize) {
82 self.builders
83 .iter_mut()
84 .for_each(|builder| builder.append_zeros(n));
85 self.validity.append_n_non_nulls(n);
86 }
87
88 fn append_nulls(&mut self, n: usize) {
89 self.builders
90 .iter_mut()
91 .for_each(|builder| builder.append_zeros(n));
94 self.validity.append_null();
95 }
96
97 fn extend_from_array(&mut self, array: &dyn Array) -> VortexResult<()> {
98 let array = array.to_struct()?;
99
100 if array.dtype() != self.dtype() {
101 vortex_bail!(
102 "Cannot extend from array with different dtype: expected {}, found {}",
103 self.dtype(),
104 array.dtype()
105 );
106 }
107
108 for (a, builder) in (0..array.struct_fields().nfields())
109 .map(|i| &array.fields()[i])
110 .zip_eq(self.builders.iter_mut())
111 {
112 a.append_to_builder(builder.as_mut())?;
113 }
114
115 self.validity.append_validity_mask(array.validity_mask()?);
116 Ok(())
117 }
118
119 fn ensure_capacity(&mut self, capacity: usize) {
120 self.builders.iter_mut().for_each(|builder| {
121 builder.ensure_capacity(capacity);
122 });
123 self.validity.ensure_capacity(capacity);
124 }
125
126 fn set_validity(&mut self, validity: Mask) {
127 self.validity = LazyNullBufferBuilder::new(validity.len());
128 self.validity.append_validity_mask(validity);
129 }
130
131 fn finish(&mut self) -> ArrayRef {
132 let len = self.len();
133 let fields = self
134 .builders
135 .iter_mut()
136 .map(|builder| builder.finish())
137 .collect::<Vec<_>>();
138
139 if fields.len() > 1 {
140 let expected_length = fields[0].len();
141 for (index, field) in fields[1..].iter().enumerate() {
142 assert_eq!(
143 field.len(),
144 expected_length,
145 "Field {index} does not have expected length {expected_length}"
146 );
147 }
148 }
149
150 let validity = self.validity.finish_with_nullability(self.nullability);
151
152 StructArray::try_new_with_dtype(fields, self.struct_dtype.clone(), len, validity)
153 .vortex_expect("Fields must all have same length.")
154 .into_array()
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use std::sync::Arc;
161
162 use vortex_dtype::PType::I32;
163 use vortex_dtype::{DType, Nullability, StructFields};
164 use vortex_scalar::Scalar;
165
166 use crate::builders::ArrayBuilder;
167 use crate::builders::struct_::StructBuilder;
168
169 #[test]
170 fn test_struct_builder() {
171 let sdt = StructFields::new(
172 vec![Arc::from("a"), Arc::from("b")].into(),
173 vec![I32.into(), I32.into()],
174 );
175 let dtype = DType::Struct(sdt.clone(), Nullability::NonNullable);
176 let mut builder = StructBuilder::with_capacity(sdt, Nullability::NonNullable, 0);
177
178 builder
179 .append_value(Scalar::struct_(dtype.clone(), vec![1.into(), 2.into()]).as_struct())
180 .unwrap();
181
182 let struct_ = builder.finish();
183 assert_eq!(struct_.len(), 1);
184 assert_eq!(struct_.dtype(), &dtype);
185 }
186
187 #[test]
188 fn test_append_nullable_struct() {
189 let sdt = StructFields::new(
190 vec![Arc::from("a"), Arc::from("b")].into(),
191 vec![I32.into(), I32.into()],
192 );
193 let dtype = DType::Struct(sdt.clone(), Nullability::Nullable);
194 let mut builder = StructBuilder::with_capacity(sdt, Nullability::Nullable, 0);
195
196 builder
197 .append_value(Scalar::struct_(dtype.clone(), vec![1.into(), 2.into()]).as_struct())
198 .unwrap();
199
200 let struct_ = builder.finish();
201 assert_eq!(struct_.len(), 1);
202 assert_eq!(struct_.dtype(), &dtype);
203 }
204}