vortex_array/builders/
struct_.rs

1use 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            // We push zero values into our children when appending a null in case the children are
92            // themselves non-nullable.
93            .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}