vortex_array/builders/
bool.rs1use std::any::Any;
5use std::mem;
6
7use vortex_buffer::BitBufferMut;
8use vortex_error::VortexExpect;
9use vortex_error::VortexResult;
10use vortex_error::vortex_ensure;
11use vortex_mask::Mask;
12
13use crate::ArrayRef;
14use crate::ExecutionCtx;
15use crate::IntoArray;
16use crate::LEGACY_SESSION;
17use crate::VortexSessionExecute;
18use crate::arrays::BoolArray;
19use crate::arrays::bool::BoolArrayExt;
20use crate::builders::ArrayBuilder;
21use crate::builders::DEFAULT_BUILDER_CAPACITY;
22use crate::builders::LazyBitBufferBuilder;
23use crate::canonical::Canonical;
24#[expect(deprecated)]
25use crate::canonical::ToCanonical as _;
26use crate::dtype::DType;
27use crate::dtype::Nullability;
28use crate::scalar::Scalar;
29
30pub struct BoolBuilder {
31 dtype: DType,
32 inner: BitBufferMut,
33 nulls: LazyBitBufferBuilder,
34}
35
36impl BoolBuilder {
37 pub fn new(nullability: Nullability) -> Self {
38 Self::with_capacity(nullability, DEFAULT_BUILDER_CAPACITY)
39 }
40
41 pub fn with_capacity(nullability: Nullability, capacity: usize) -> Self {
42 Self {
43 inner: BitBufferMut::with_capacity(capacity),
44 nulls: LazyBitBufferBuilder::new(capacity),
45 dtype: DType::Bool(nullability),
46 }
47 }
48
49 pub fn append_value(&mut self, value: bool) {
51 self.append_values(value, 1)
52 }
53
54 pub fn append_values(&mut self, value: bool, n: usize) {
58 self.inner.append_n(value, n);
59 self.nulls.append_n_non_nulls(n)
60 }
61
62 pub fn finish_into_bool(&mut self) -> BoolArray {
64 assert_eq!(
65 self.nulls.len(),
66 self.inner.len(),
67 "Null count and value count should match when calling BoolBuilder::finish."
68 );
69
70 BoolArray::new(
71 mem::take(&mut self.inner).freeze(),
72 self.nulls.finish_with_nullability(self.dtype.nullability()),
73 )
74 }
75
76 pub(crate) fn append_bool_array(
77 &mut self,
78 array: &BoolArray,
79 ctx: &mut ExecutionCtx,
80 ) -> VortexResult<()> {
81 self.inner.append_buffer(&array.to_bit_buffer());
82 self.nulls
83 .append_validity_mask(&BoolArrayExt::validity(array).execute_mask(array.len(), ctx)?);
84 Ok(())
85 }
86}
87
88impl ArrayBuilder for BoolBuilder {
89 fn as_any(&self) -> &dyn Any {
90 self
91 }
92
93 fn as_any_mut(&mut self) -> &mut dyn Any {
94 self
95 }
96
97 fn dtype(&self) -> &DType {
98 &self.dtype
99 }
100
101 fn len(&self) -> usize {
102 self.inner.len()
103 }
104
105 fn append_zeros(&mut self, n: usize) {
106 self.append_values(false, n)
107 }
108
109 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
110 self.inner.append_n(false, n);
111 self.nulls.append_n_nulls(n)
112 }
113
114 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
115 vortex_ensure!(
116 scalar.dtype() == self.dtype(),
117 "BoolBuilder expected scalar with dtype {}, got {}",
118 self.dtype(),
119 scalar.dtype()
120 );
121
122 match scalar.as_bool().value() {
123 Some(value) => self.append_value(value),
124 None => self.append_null(),
125 }
126
127 Ok(())
128 }
129
130 unsafe fn extend_from_array_unchecked(&mut self, array: &ArrayRef) {
131 #[expect(deprecated)]
132 let bool_array = array.to_bool();
133 self.append_bool_array(&bool_array, &mut LEGACY_SESSION.create_execution_ctx())
134 .vortex_expect("Failed to append bool array");
135 }
136
137 fn reserve_exact(&mut self, additional: usize) {
138 self.inner.reserve(additional);
139 self.nulls.reserve_exact(additional);
140 }
141
142 unsafe fn set_validity_unchecked(&mut self, validity: Mask) {
143 self.nulls = LazyBitBufferBuilder::from_validity_mask(validity);
144 }
145
146 fn finish(&mut self) -> ArrayRef {
147 self.finish_into_bool().into_array()
148 }
149
150 fn finish_into_canonical(&mut self) -> Canonical {
151 Canonical::Bool(self.finish_into_bool())
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use rand::RngExt;
158 use rand::SeedableRng;
159 use rand::prelude::StdRng;
160 use vortex_error::VortexResult;
161
162 use crate::ArrayRef;
163 use crate::IntoArray;
164 use crate::VortexSessionExecute;
165 use crate::array_session;
166 use crate::arrays::ChunkedArray;
167 use crate::arrays::bool::BoolArrayExt;
168 use crate::assert_arrays_eq;
169 use crate::builders::ArrayBuilder;
170 use crate::builders::BoolBuilder;
171 use crate::builders::bool::BoolArray;
172 use crate::builders::builder_with_capacity;
173 #[expect(deprecated)]
174 use crate::canonical::ToCanonical as _;
175 use crate::dtype::DType;
176 use crate::dtype::Nullability;
177 use crate::scalar::Scalar;
178
179 fn make_opt_bool_chunks(len: usize, chunk_count: usize) -> ArrayRef {
180 let mut rng = StdRng::seed_from_u64(0);
181
182 (0..chunk_count)
183 .map(|_| {
184 BoolArray::from_iter((0..len).map(|_| match rng.random_range::<u8, _>(0..=2) {
185 0 => Some(false),
186 1 => Some(true),
187 2 => None,
188 _ => unreachable!(),
189 }))
190 .into_array()
191 })
192 .collect::<ChunkedArray>()
193 .into_array()
194 }
195
196 #[test]
197 fn tests() -> VortexResult<()> {
198 let len = 1000;
199 let chunk_count = 10;
200 let chunk = make_opt_bool_chunks(len, chunk_count);
201
202 let mut ctx = array_session().create_execution_ctx();
203 let mut builder = builder_with_capacity(chunk.dtype(), len * chunk_count);
204 chunk
205 .clone()
206 .append_to_builder(builder.as_mut(), &mut ctx)?;
207
208 #[expect(deprecated)]
209 let canon_into = builder.finish().to_bool();
210 #[expect(deprecated)]
211 let into_canon = chunk.to_bool();
212
213 assert!(canon_into.validity()?.mask_eq(
214 &into_canon.validity()?,
215 canon_into.len(),
216 &mut ctx
217 )?);
218 assert_eq!(canon_into.to_bit_buffer(), into_canon.to_bit_buffer());
219 Ok(())
220 }
221
222 #[test]
223 fn test_append_scalar() {
224 let mut ctx = array_session().create_execution_ctx();
225 let mut builder = BoolBuilder::with_capacity(Nullability::Nullable, 10);
226
227 let true_scalar = Scalar::bool(true, Nullability::Nullable);
229 builder.append_scalar(&true_scalar).unwrap();
230
231 let false_scalar = Scalar::bool(false, Nullability::Nullable);
233 builder.append_scalar(&false_scalar).unwrap();
234
235 let null_scalar = Scalar::null(DType::Bool(Nullability::Nullable));
237 builder.append_scalar(&null_scalar).unwrap();
238
239 let array = builder.finish_into_bool();
240 let expected = BoolArray::from_iter([Some(true), Some(false), None]);
241 assert_arrays_eq!(&array, &expected, &mut ctx);
242
243 let mut builder = BoolBuilder::with_capacity(Nullability::NonNullable, 10);
245 let wrong_scalar = Scalar::from(42i32);
246 assert!(builder.append_scalar(&wrong_scalar).is_err());
247 }
248}