1use crate::builder::ArrayBuilder;
6use crate::builder::buffer_builder::{Int8BufferBuilder, Int32BufferBuilder};
7use crate::{ArrayRef, ArrowPrimitiveType, UnionArray, make_array};
8use arrow_buffer::NullBufferBuilder;
9use arrow_buffer::{ArrowNativeType, Buffer, ScalarBuffer};
10use arrow_data::ArrayDataBuilder;
11use arrow_schema::{ArrowError, DataType, Field};
12use std::any::Any;
13use std::collections::BTreeMap;
14use std::sync::Arc;
15
16#[derive(Debug)]
18struct FieldData {
19 type_id: i8,
21 data_type: DataType,
23 values_buffer: Box<dyn FieldDataValues>,
25 slots: usize,
27 null_buffer_builder: NullBufferBuilder,
29}
30
31trait FieldDataValues: std::fmt::Debug + Send + Sync {
33 fn as_mut_any(&mut self) -> &mut dyn Any;
34
35 fn append_null(&mut self);
36
37 fn finish(&mut self) -> Buffer;
38
39 fn finish_cloned(&self) -> Buffer;
40}
41
42impl<T: ArrowNativeType> FieldDataValues for Vec<T> {
43 fn as_mut_any(&mut self) -> &mut dyn Any {
44 self
45 }
46
47 fn append_null(&mut self) {
48 self.push(T::default())
49 }
50
51 fn finish(&mut self) -> Buffer {
52 Buffer::from_vec(std::mem::take(self))
53 }
54
55 fn finish_cloned(&self) -> Buffer {
56 Buffer::from_slice_ref(self.as_slice())
57 }
58}
59
60impl FieldData {
61 fn new<T: ArrowPrimitiveType>(type_id: i8, data_type: DataType, capacity: usize) -> Self {
63 Self {
64 type_id,
65 data_type,
66 slots: 0,
67 values_buffer: Box::new(Vec::<T::Native>::with_capacity(capacity)),
68 null_buffer_builder: NullBufferBuilder::new(capacity),
69 }
70 }
71
72 fn append_value<T: ArrowPrimitiveType>(&mut self, v: T::Native) {
74 self.values_buffer
75 .as_mut_any()
76 .downcast_mut::<Vec<T::Native>>()
77 .expect("Tried to append unexpected type")
78 .push(v);
79
80 self.null_buffer_builder.append(true);
81 self.slots += 1;
82 }
83
84 fn append_null(&mut self) {
86 self.values_buffer.append_null();
87 self.null_buffer_builder.append(false);
88 self.slots += 1;
89 }
90}
91
92#[derive(Debug, Default)]
135pub struct UnionBuilder {
136 len: usize,
138 fields: BTreeMap<String, FieldData>,
140 type_id_builder: Int8BufferBuilder,
142 value_offset_builder: Option<Int32BufferBuilder>,
144 initial_capacity: usize,
145}
146
147impl UnionBuilder {
148 pub fn new_dense() -> Self {
150 Self::with_capacity_dense(1024)
151 }
152
153 pub fn new_sparse() -> Self {
155 Self::with_capacity_sparse(1024)
156 }
157
158 pub fn with_capacity_dense(capacity: usize) -> Self {
160 Self {
161 len: 0,
162 fields: Default::default(),
163 type_id_builder: Int8BufferBuilder::new(capacity),
164 value_offset_builder: Some(Int32BufferBuilder::new(capacity)),
165 initial_capacity: capacity,
166 }
167 }
168
169 pub fn with_capacity_sparse(capacity: usize) -> Self {
171 Self {
172 len: 0,
173 fields: Default::default(),
174 type_id_builder: Int8BufferBuilder::new(capacity),
175 value_offset_builder: None,
176 initial_capacity: capacity,
177 }
178 }
179
180 #[inline]
188 pub fn append_null<T: ArrowPrimitiveType>(
189 &mut self,
190 type_name: &str,
191 ) -> Result<(), ArrowError> {
192 self.append_option::<T>(type_name, None)
193 }
194
195 #[inline]
197 pub fn append<T: ArrowPrimitiveType>(
198 &mut self,
199 type_name: &str,
200 v: T::Native,
201 ) -> Result<(), ArrowError> {
202 self.append_option::<T>(type_name, Some(v))
203 }
204
205 fn append_option<T: ArrowPrimitiveType>(
206 &mut self,
207 type_name: &str,
208 v: Option<T::Native>,
209 ) -> Result<(), ArrowError> {
210 let type_name = type_name.to_string();
211
212 let mut field_data = match self.fields.remove(&type_name) {
213 Some(data) => {
214 if data.data_type != T::DATA_TYPE {
215 return Err(ArrowError::InvalidArgumentError(format!(
216 "Attempt to write col \"{}\" with type {} doesn't match existing type {}",
217 type_name,
218 T::DATA_TYPE,
219 data.data_type
220 )));
221 }
222 data
223 }
224 None => match self.value_offset_builder {
225 Some(_) => FieldData::new::<T>(
226 self.fields.len() as i8,
227 T::DATA_TYPE,
228 self.initial_capacity,
229 ),
230 None => {
232 let mut fd = FieldData::new::<T>(
233 self.fields.len() as i8,
234 T::DATA_TYPE,
235 self.len.max(self.initial_capacity),
236 );
237 for _ in 0..self.len {
238 fd.append_null();
239 }
240 fd
241 }
242 },
243 };
244 self.type_id_builder.append(field_data.type_id);
245
246 match &mut self.value_offset_builder {
247 Some(offset_builder) => {
249 offset_builder.append(field_data.slots as i32);
250 }
251 None => {
253 for fd in self.fields.values_mut() {
254 fd.append_null();
256 }
257 }
258 }
259
260 match v {
261 Some(v) => field_data.append_value::<T>(v),
262 None => field_data.append_null(),
263 }
264
265 self.fields.insert(type_name, field_data);
266 self.len += 1;
267 Ok(())
268 }
269
270 pub fn build(self) -> Result<UnionArray, ArrowError> {
272 let mut children = Vec::with_capacity(self.fields.len());
273 let union_fields = self
274 .fields
275 .into_iter()
276 .map(
277 |(
278 name,
279 FieldData {
280 type_id,
281 data_type,
282 mut values_buffer,
283 slots,
284 mut null_buffer_builder,
285 },
286 )| {
287 let array_ref = make_array(unsafe {
289 ArrayDataBuilder::new(data_type.clone())
290 .add_buffer(values_buffer.finish())
291 .len(slots)
292 .nulls(null_buffer_builder.finish())
293 .build_unchecked()
294 });
295 children.push(array_ref);
296 (type_id, Arc::new(Field::new(name, data_type, false)))
297 },
298 )
299 .collect();
300 UnionArray::try_new(
301 union_fields,
302 self.type_id_builder.into(),
303 self.value_offset_builder.map(Into::into),
304 children,
305 )
306 }
307
308 fn build_cloned(&self) -> Result<UnionArray, ArrowError> {
312 let mut children = Vec::with_capacity(self.fields.len());
313 let union_fields: Vec<_> = self
314 .fields
315 .iter()
316 .map(|(name, field_data)| {
317 let FieldData {
318 type_id,
319 data_type,
320 values_buffer,
321 slots,
322 null_buffer_builder,
323 } = field_data;
324
325 let array_ref = make_array(unsafe {
327 ArrayDataBuilder::new(data_type.clone())
328 .add_buffer(values_buffer.finish_cloned())
329 .len(*slots)
330 .nulls(null_buffer_builder.finish_cloned())
331 .build_unchecked()
332 });
333 children.push(array_ref);
334 (
335 *type_id,
336 Arc::new(Field::new(name.clone(), data_type.clone(), false)),
337 )
338 })
339 .collect();
340 UnionArray::try_new(
341 union_fields.into_iter().collect(),
342 ScalarBuffer::from(self.type_id_builder.as_slice().to_vec()),
343 self.value_offset_builder
344 .as_ref()
345 .map(|builder| ScalarBuffer::from(builder.as_slice().to_vec())),
346 children,
347 )
348 }
349}
350
351impl ArrayBuilder for UnionBuilder {
352 fn len(&self) -> usize {
354 self.len
355 }
356
357 fn finish(&mut self) -> ArrayRef {
359 let builder = std::mem::take(self);
361
362 Arc::new(builder.build().unwrap())
364 }
365
366 fn finish_cloned(&self) -> ArrayRef {
368 Arc::new(
371 self.build_cloned().unwrap_or_else(|err| {
372 panic!("UnionBuilder::build_cloned failed unexpectedly: {err}")
373 }),
374 )
375 }
376
377 fn as_any(&self) -> &dyn Any {
379 self
380 }
381
382 fn as_any_mut(&mut self) -> &mut dyn Any {
384 self
385 }
386
387 fn into_box_any(self: Box<Self>) -> Box<dyn Any> {
389 self
390 }
391}
392
393#[cfg(test)]
394mod tests {
395 use super::*;
396 use crate::array::Array;
397 use crate::cast::AsArray;
398 use crate::types::{Float64Type, Int32Type};
399
400 #[test]
401 fn test_union_builder_array_builder_trait() {
402 let mut builder = UnionBuilder::new_dense();
404
405 builder.append::<Int32Type>("a", 1).unwrap();
407 builder.append::<Float64Type>("b", 3.0).unwrap();
408 builder.append::<Int32Type>("a", 4).unwrap();
409
410 assert_eq!(builder.len(), 3);
411
412 let array1 = builder.finish_cloned();
414 assert_eq!(array1.len(), 3);
415
416 let union1 = array1.as_any().downcast_ref::<UnionArray>().unwrap();
418 assert_eq!(union1.type_ids(), &[0, 1, 0]);
419 assert_eq!(union1.offsets().unwrap().as_ref(), &[0, 0, 1]);
420 let int_array1 = union1.child(0).as_primitive::<Int32Type>();
421 let float_array1 = union1.child(1).as_primitive::<Float64Type>();
422 assert_eq!(int_array1.value(0), 1);
423 assert_eq!(int_array1.value(1), 4);
424 assert_eq!(float_array1.value(0), 3.0);
425
426 builder.append::<Float64Type>("b", 5.0).unwrap();
428 assert_eq!(builder.len(), 4);
429
430 let array2 = builder.finish();
432 assert_eq!(array2.len(), 4);
433
434 let union2 = array2.as_any().downcast_ref::<UnionArray>().unwrap();
436 assert_eq!(union2.type_ids(), &[0, 1, 0, 1]);
437 assert_eq!(union2.offsets().unwrap().as_ref(), &[0, 0, 1, 1]);
438 let int_array2 = union2.child(0).as_primitive::<Int32Type>();
439 let float_array2 = union2.child(1).as_primitive::<Float64Type>();
440 assert_eq!(int_array2.value(0), 1);
441 assert_eq!(int_array2.value(1), 4);
442 assert_eq!(float_array2.value(0), 3.0);
443 assert_eq!(float_array2.value(1), 5.0);
444 }
445
446 #[test]
447 fn test_union_builder_type_erased() {
448 let mut builders: Vec<Box<dyn ArrayBuilder>> = vec![Box::new(UnionBuilder::new_sparse())];
450
451 let union_builder = builders[0]
453 .as_any_mut()
454 .downcast_mut::<UnionBuilder>()
455 .unwrap();
456 union_builder.append::<Int32Type>("x", 10).unwrap();
457 union_builder.append::<Float64Type>("y", 20.0).unwrap();
458
459 assert_eq!(builders[0].len(), 2);
460
461 let result = builders
462 .into_iter()
463 .map(|mut b| b.finish())
464 .collect::<Vec<_>>();
465 assert_eq!(result[0].len(), 2);
466
467 let union = result[0].as_any().downcast_ref::<UnionArray>().unwrap();
469 assert_eq!(union.type_ids(), &[0, 1]);
470 assert!(union.offsets().is_none()); let int_array = union.child(0).as_primitive::<Int32Type>();
472 let float_array = union.child(1).as_primitive::<Float64Type>();
473 assert_eq!(int_array.value(0), 10);
474 assert!(int_array.is_null(1)); assert!(float_array.is_null(0)); assert_eq!(float_array.value(1), 20.0);
477 }
478}