• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vortex-data / vortex / 16992684502

15 Aug 2025 02:56PM UTC coverage: 87.875% (+0.2%) from 87.72%
16992684502

Pull #2456

github

web-flow
Merge 2d540e578 into 4a23f65b3
Pull Request #2456: feat: basic BoolBuffer / BoolBufferMut

1275 of 1428 new or added lines in 110 files covered. (89.29%)

334 existing lines in 31 files now uncovered.

57169 of 65057 relevant lines covered (87.88%)

658056.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.71
/vortex-array/src/builders/struct_.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
use std::any::Any;
5

6
use itertools::Itertools;
7
use vortex_dtype::{DType, Nullability, StructFields};
8
use vortex_error::{VortexExpect, VortexResult, vortex_bail};
9
use vortex_mask::Mask;
10
use vortex_scalar::StructScalar;
11

12
use crate::arrays::StructArray;
13
use crate::builders::lazy_validity_builder::LazyBitBufferBuilder;
14
use crate::builders::{ArrayBuilder, ArrayBuilderExt, builder_with_capacity};
15
use crate::{Array, ArrayRef, IntoArray, ToCanonical};
16

17
pub struct StructBuilder {
18
    builders: Vec<Box<dyn ArrayBuilder>>,
19
    validity: LazyBitBufferBuilder,
20
    struct_dtype: StructFields,
21
    nullability: Nullability,
22
    dtype: DType,
23
}
24

25
impl StructBuilder {
26
    pub fn with_capacity(
278✔
27
        struct_dtype: StructFields,
278✔
28
        nullability: Nullability,
278✔
29
        capacity: usize,
278✔
30
    ) -> Self {
278✔
31
        let builders = struct_dtype
278✔
32
            .fields()
278✔
33
            .map(|dt| builder_with_capacity(&dt, capacity))
305✔
34
            .collect();
278✔
35

36
        Self {
278✔
37
            builders,
278✔
38
            validity: LazyBitBufferBuilder::new(capacity),
278✔
39
            struct_dtype: struct_dtype.clone(),
278✔
40
            nullability,
278✔
41
            dtype: DType::Struct(struct_dtype, nullability),
278✔
42
        }
278✔
43
    }
278✔
44

45
    pub fn append_value(&mut self, struct_scalar: StructScalar) -> VortexResult<()> {
2✔
46
        if struct_scalar.dtype() != &DType::Struct(self.struct_dtype.clone(), self.nullability) {
2✔
47
            vortex_bail!(
×
48
                "Expected struct scalar with dtype {:?}, found {:?}",
×
49
                self.struct_dtype,
50
                struct_scalar.dtype()
×
51
            )
52
        }
2✔
53

54
        if let Some(fields) = struct_scalar.fields() {
2✔
55
            for (builder, field) in self.builders.iter_mut().zip_eq(fields) {
4✔
56
                builder.append_scalar(&field)?;
4✔
57
            }
58
            self.validity.append_non_null();
2✔
59
        } else {
60
            self.append_null()
×
61
        }
62

63
        Ok(())
2✔
64
    }
2✔
65
}
66

67
impl ArrayBuilder for StructBuilder {
68
    fn as_any(&self) -> &dyn Any {
×
69
        self
×
70
    }
×
71

72
    fn as_any_mut(&mut self) -> &mut dyn Any {
×
73
        self
×
74
    }
×
75

76
    fn dtype(&self) -> &DType {
×
77
        &self.dtype
×
78
    }
×
79

80
    fn len(&self) -> usize {
278✔
81
        self.validity.len()
278✔
82
    }
278✔
83

84
    fn append_zeros(&mut self, n: usize) {
×
85
        self.builders
×
86
            .iter_mut()
×
87
            .for_each(|builder| builder.append_zeros(n));
×
88
        self.validity.append_n_non_nulls(n);
×
89
    }
×
90

91
    fn append_nulls(&mut self, n: usize) {
156✔
92
        self.builders
156✔
93
            .iter_mut()
156✔
94
            // We push zero values into our children when appending a null in case the children are
95
            // themselves non-nullable.
96
            .for_each(|builder| builder.append_zeros(n));
156✔
97
        self.validity.append_null();
156✔
98
    }
156✔
99

100
    fn extend_from_array(&mut self, array: &dyn Array) -> VortexResult<()> {
×
101
        let array = array.to_struct()?;
×
102

103
        if array.dtype() != self.dtype() {
×
104
            vortex_bail!(
×
105
                "Cannot extend from array with different dtype: expected {}, found {}",
×
106
                self.dtype(),
×
107
                array.dtype()
×
108
            );
109
        }
×
110

111
        for (a, builder) in (0..array.struct_fields().nfields())
×
112
            .map(|i| &array.fields()[i])
×
113
            .zip_eq(self.builders.iter_mut())
×
114
        {
115
            a.append_to_builder(builder.as_mut())?;
×
116
        }
117

118
        self.validity.append_validity_mask(array.validity_mask()?);
×
119
        Ok(())
×
120
    }
×
121

122
    fn ensure_capacity(&mut self, capacity: usize) {
×
123
        self.builders.iter_mut().for_each(|builder| {
×
124
            builder.ensure_capacity(capacity);
×
125
        });
×
126
        self.validity.ensure_capacity(capacity);
×
127
    }
×
128

129
    fn set_validity(&mut self, validity: Mask) {
×
NEW
130
        self.validity = LazyBitBufferBuilder::new(validity.len());
×
131
        self.validity.append_validity_mask(validity);
×
132
    }
×
133

134
    fn finish(&mut self) -> ArrayRef {
278✔
135
        let len = self.len();
278✔
136
        let fields = self
278✔
137
            .builders
278✔
138
            .iter_mut()
278✔
139
            .map(|builder| builder.finish())
305✔
140
            .collect::<Vec<_>>();
278✔
141

142
        if fields.len() > 1 {
278✔
143
            let expected_length = fields[0].len();
31✔
144
            for (index, field) in fields[1..].iter().enumerate() {
37✔
145
                assert_eq!(
37✔
146
                    field.len(),
37✔
147
                    expected_length,
148
                    "Field {index} does not have expected length {expected_length}"
×
149
                );
150
            }
151
        }
247✔
152

153
        let validity = self.validity.finish_with_nullability(self.nullability);
278✔
154

155
        StructArray::try_new_with_dtype(fields, self.struct_dtype.clone(), len, validity)
278✔
156
            .vortex_expect("Fields must all have same length.")
278✔
157
            .into_array()
278✔
158
    }
278✔
159
}
160

161
#[cfg(test)]
162
mod tests {
163
    use std::sync::Arc;
164

165
    use vortex_dtype::PType::I32;
166
    use vortex_dtype::{DType, Nullability, StructFields};
167
    use vortex_scalar::Scalar;
168

169
    use crate::builders::ArrayBuilder;
170
    use crate::builders::struct_::StructBuilder;
171

172
    #[test]
173
    fn test_struct_builder() {
1✔
174
        let sdt = StructFields::new(
1✔
175
            vec![Arc::from("a"), Arc::from("b")].into(),
1✔
176
            vec![I32.into(), I32.into()],
1✔
177
        );
178
        let dtype = DType::Struct(sdt.clone(), Nullability::NonNullable);
1✔
179
        let mut builder = StructBuilder::with_capacity(sdt, Nullability::NonNullable, 0);
1✔
180

181
        builder
1✔
182
            .append_value(Scalar::struct_(dtype.clone(), vec![1.into(), 2.into()]).as_struct())
1✔
183
            .unwrap();
1✔
184

185
        let struct_ = builder.finish();
1✔
186
        assert_eq!(struct_.len(), 1);
1✔
187
        assert_eq!(struct_.dtype(), &dtype);
1✔
188
    }
1✔
189

190
    #[test]
191
    fn test_append_nullable_struct() {
1✔
192
        let sdt = StructFields::new(
1✔
193
            vec![Arc::from("a"), Arc::from("b")].into(),
1✔
194
            vec![I32.into(), I32.into()],
1✔
195
        );
196
        let dtype = DType::Struct(sdt.clone(), Nullability::Nullable);
1✔
197
        let mut builder = StructBuilder::with_capacity(sdt, Nullability::Nullable, 0);
1✔
198

199
        builder
1✔
200
            .append_value(Scalar::struct_(dtype.clone(), vec![1.into(), 2.into()]).as_struct())
1✔
201
            .unwrap();
1✔
202

203
        let struct_ = builder.finish();
1✔
204
        assert_eq!(struct_.len(), 1);
1✔
205
        assert_eq!(struct_.dtype(), &dtype);
1✔
206
    }
1✔
207
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc