1#![allow(clippy::enum_clike_unportable_variant)]
18
19use crate::{Array, ArrayRef, make_array};
20use arrow_buffer::bit_chunk_iterator::{BitChunkIterator, BitChunks};
21use arrow_buffer::buffer::NullBuffer;
22use arrow_buffer::{BooleanBuffer, MutableBuffer, ScalarBuffer};
23use arrow_data::{ArrayData, ArrayDataBuilder};
24use arrow_schema::{ArrowError, DataType, UnionFields, UnionMode};
25use std::any::Any;
28use std::collections::HashSet;
29use std::sync::Arc;
30
31#[derive(Clone)]
123pub struct UnionArray {
124 data_type: DataType,
125 type_ids: ScalarBuffer<i8>,
126 offsets: Option<ScalarBuffer<i32>>,
127 fields: Vec<Option<ArrayRef>>,
128}
129
130impl UnionArray {
131 pub unsafe fn new_unchecked(
150 fields: UnionFields,
151 type_ids: ScalarBuffer<i8>,
152 offsets: Option<ScalarBuffer<i32>>,
153 children: Vec<ArrayRef>,
154 ) -> Self {
155 let mode = if offsets.is_some() {
156 UnionMode::Dense
157 } else {
158 UnionMode::Sparse
159 };
160
161 let len = type_ids.len();
162 let builder = ArrayData::builder(DataType::Union(fields, mode))
163 .add_buffer(type_ids.into_inner())
164 .child_data(children.into_iter().map(Array::into_data).collect())
165 .len(len);
166
167 let data = match offsets {
168 Some(offsets) => unsafe { builder.add_buffer(offsets.into_inner()).build_unchecked() },
169 None => unsafe { builder.build_unchecked() },
170 };
171 Self::from(data)
172 }
173
174 pub fn try_new(
178 fields: UnionFields,
179 type_ids: ScalarBuffer<i8>,
180 offsets: Option<ScalarBuffer<i32>>,
181 children: Vec<ArrayRef>,
182 ) -> Result<Self, ArrowError> {
183 if fields.len() != children.len() {
185 return Err(ArrowError::InvalidArgumentError(
186 "Union fields length must match child arrays length".to_string(),
187 ));
188 }
189
190 if let Some(offsets) = &offsets {
191 if offsets.len() != type_ids.len() {
193 return Err(ArrowError::InvalidArgumentError(
194 "Type Ids and Offsets lengths must match".to_string(),
195 ));
196 }
197 } else {
198 for child in &children {
200 if child.len() != type_ids.len() {
201 return Err(ArrowError::InvalidArgumentError(
202 "Sparse union child arrays must be equal in length to the length of the union".to_string(),
203 ));
204 }
205 }
206 }
207
208 let max_id = fields.iter().map(|(i, _)| i).max().unwrap_or_default() as usize;
210 let mut array_lens = vec![i32::MIN; max_id + 1];
211 for (cd, (field_id, _)) in children.iter().zip(fields.iter()) {
212 array_lens[field_id as usize] = cd.len() as i32;
213 }
214
215 for id in &type_ids {
217 match array_lens.get(*id as usize) {
218 Some(x) if *x != i32::MIN => {}
219 _ => {
220 return Err(ArrowError::InvalidArgumentError(
221 "Type Ids values must match one of the field type ids".to_owned(),
222 ));
223 }
224 }
225 }
226
227 if let Some(offsets) = &offsets {
229 let mut iter = type_ids.iter().zip(offsets.iter());
230 if iter.any(|(type_id, &offset)| offset < 0 || offset >= array_lens[*type_id as usize])
231 {
232 return Err(ArrowError::InvalidArgumentError(
233 "Offsets must be non-negative and within the length of the Array".to_owned(),
234 ));
235 }
236 }
237
238 let union_array = unsafe { Self::new_unchecked(fields, type_ids, offsets, children) };
241 Ok(union_array)
242 }
243
244 pub fn child(&self, type_id: i8) -> &ArrayRef {
251 assert!((type_id as usize) < self.fields.len());
252 let boxed = &self.fields[type_id as usize];
253 boxed.as_ref().expect("invalid type id")
254 }
255
256 pub fn type_id(&self, index: usize) -> i8 {
262 assert!(index < self.type_ids.len());
263 self.type_ids[index]
264 }
265
266 pub fn type_ids(&self) -> &ScalarBuffer<i8> {
268 &self.type_ids
269 }
270
271 pub fn offsets(&self) -> Option<&ScalarBuffer<i32>> {
273 self.offsets.as_ref()
274 }
275
276 pub fn value_offset(&self, index: usize) -> usize {
282 assert!(index < self.len());
283 match &self.offsets {
284 Some(offsets) => offsets[index] as usize,
285 None => self.offset() + index,
286 }
287 }
288
289 pub fn value(&self, i: usize) -> ArrayRef {
297 let type_id = self.type_id(i);
298 let value_offset = self.value_offset(i);
299 let child = self.child(type_id);
300 child.slice(value_offset, 1)
301 }
302
303 pub fn type_names(&self) -> Vec<&str> {
305 match self.data_type() {
306 DataType::Union(fields, _) => fields
307 .iter()
308 .map(|(_, f)| f.name().as_str())
309 .collect::<Vec<&str>>(),
310 _ => unreachable!("Union array's data type is not a union!"),
311 }
312 }
313
314 pub fn fields(&self) -> &UnionFields {
316 match self.data_type() {
317 DataType::Union(fields, _) => fields,
318 _ => unreachable!("Union array's data type is not a union!"),
319 }
320 }
321
322 pub fn is_dense(&self) -> bool {
324 match self.data_type() {
325 DataType::Union(_, mode) => mode == &UnionMode::Dense,
326 _ => unreachable!("Union array's data type is not a union!"),
327 }
328 }
329
330 pub fn slice(&self, offset: usize, length: usize) -> Self {
332 let (offsets, fields) = match self.offsets.as_ref() {
333 Some(offsets) => (Some(offsets.slice(offset, length)), self.fields.clone()),
335 None => {
337 let fields = self
338 .fields
339 .iter()
340 .map(|x| x.as_ref().map(|x| x.slice(offset, length)))
341 .collect();
342 (None, fields)
343 }
344 };
345
346 Self {
347 data_type: self.data_type.clone(),
348 type_ids: self.type_ids.slice(offset, length),
349 offsets,
350 fields,
351 }
352 }
353
354 #[allow(clippy::type_complexity)]
382 pub fn into_parts(
383 self,
384 ) -> (
385 UnionFields,
386 ScalarBuffer<i8>,
387 Option<ScalarBuffer<i32>>,
388 Vec<ArrayRef>,
389 ) {
390 let Self {
391 data_type,
392 type_ids,
393 offsets,
394 mut fields,
395 } = self;
396 match data_type {
397 DataType::Union(union_fields, _) => {
398 let children = union_fields
399 .iter()
400 .map(|(type_id, _)| fields[type_id as usize].take().unwrap())
401 .collect();
402 (union_fields, type_ids, offsets, children)
403 }
404 _ => unreachable!(),
405 }
406 }
407
408 fn mask_sparse_skip_without_nulls(&self, nulls: Vec<(i8, NullBuffer)>) -> BooleanBuffer {
410 let fold = |(with_nulls_selected, union_nulls), (is_field, field_nulls)| {
416 (
417 with_nulls_selected | is_field,
418 union_nulls | (is_field & field_nulls),
419 )
420 };
421
422 self.mask_sparse_helper(
423 nulls,
424 |type_ids_chunk_array, nulls_masks_iters| {
425 let (with_nulls_selected, union_nulls) = nulls_masks_iters
426 .iter_mut()
427 .map(|(field_type_id, field_nulls)| {
428 let field_nulls = field_nulls.next().unwrap();
429 let is_field = selection_mask(type_ids_chunk_array, *field_type_id);
430
431 (is_field, field_nulls)
432 })
433 .fold((0, 0), fold);
434
435 let without_nulls_selected = !with_nulls_selected;
437
438 without_nulls_selected | union_nulls
441 },
442 |type_ids_remainder, bit_chunks| {
443 let (with_nulls_selected, union_nulls) = bit_chunks
444 .iter()
445 .map(|(field_type_id, field_bit_chunks)| {
446 let field_nulls = field_bit_chunks.remainder_bits();
447 let is_field = selection_mask(type_ids_remainder, *field_type_id);
448
449 (is_field, field_nulls)
450 })
451 .fold((0, 0), fold);
452
453 let without_nulls_selected = !with_nulls_selected;
454
455 without_nulls_selected | union_nulls
456 },
457 )
458 }
459
460 fn mask_sparse_skip_fully_null(&self, mut nulls: Vec<(i8, NullBuffer)>) -> BooleanBuffer {
462 let fields = match self.data_type() {
463 DataType::Union(fields, _) => fields,
464 _ => unreachable!("Union array's data type is not a union!"),
465 };
466
467 let type_ids = fields.iter().map(|(id, _)| id).collect::<HashSet<_>>();
468 let with_nulls = nulls.iter().map(|(id, _)| *id).collect::<HashSet<_>>();
469
470 let without_nulls_ids = type_ids
471 .difference(&with_nulls)
472 .copied()
473 .collect::<Vec<_>>();
474
475 nulls.retain(|(_, nulls)| nulls.null_count() < nulls.len());
476
477 self.mask_sparse_helper(
482 nulls,
483 |type_ids_chunk_array, nulls_masks_iters| {
484 let union_nulls = nulls_masks_iters.iter_mut().fold(
485 0,
486 |union_nulls, (field_type_id, nulls_iter)| {
487 let field_nulls = nulls_iter.next().unwrap();
488
489 if field_nulls == 0 {
490 union_nulls
491 } else {
492 let is_field = selection_mask(type_ids_chunk_array, *field_type_id);
493
494 union_nulls | (is_field & field_nulls)
495 }
496 },
497 );
498
499 let without_nulls_selected =
501 without_nulls_selected(type_ids_chunk_array, &without_nulls_ids);
502
503 union_nulls | without_nulls_selected
506 },
507 |type_ids_remainder, bit_chunks| {
508 let union_nulls =
509 bit_chunks
510 .iter()
511 .fold(0, |union_nulls, (field_type_id, field_bit_chunks)| {
512 let is_field = selection_mask(type_ids_remainder, *field_type_id);
513 let field_nulls = field_bit_chunks.remainder_bits();
514
515 union_nulls | is_field & field_nulls
516 });
517
518 union_nulls | without_nulls_selected(type_ids_remainder, &without_nulls_ids)
519 },
520 )
521 }
522
523 fn mask_sparse_all_with_nulls_skip_one(&self, nulls: Vec<(i8, NullBuffer)>) -> BooleanBuffer {
525 self.mask_sparse_helper(
532 nulls,
533 |type_ids_chunk_array, nulls_masks_iters| {
534 let (is_not_first, union_nulls) = nulls_masks_iters[1..] .iter_mut()
536 .fold(
537 (0, 0),
538 |(is_not_first, union_nulls), (field_type_id, nulls_iter)| {
539 let field_nulls = nulls_iter.next().unwrap();
540 let is_field = selection_mask(type_ids_chunk_array, *field_type_id);
541
542 (
543 is_not_first | is_field,
544 union_nulls | (is_field & field_nulls),
545 )
546 },
547 );
548
549 let is_first = !is_not_first;
550 let first_nulls = nulls_masks_iters[0].1.next().unwrap();
551
552 (is_first & first_nulls) | union_nulls
553 },
554 |type_ids_remainder, bit_chunks| {
555 bit_chunks
556 .iter()
557 .fold(0, |union_nulls, (field_type_id, field_bit_chunks)| {
558 let field_nulls = field_bit_chunks.remainder_bits();
559 let is_field = selection_mask(type_ids_remainder, *field_type_id);
562
563 union_nulls | (is_field & field_nulls)
564 })
565 },
566 )
567 }
568
569 fn mask_sparse_helper(
572 &self,
573 nulls: Vec<(i8, NullBuffer)>,
574 mut mask_chunk: impl FnMut(&[i8; 64], &mut [(i8, BitChunkIterator)]) -> u64,
575 mask_remainder: impl FnOnce(&[i8], &[(i8, BitChunks)]) -> u64,
576 ) -> BooleanBuffer {
577 let bit_chunks = nulls
578 .iter()
579 .map(|(type_id, nulls)| (*type_id, nulls.inner().bit_chunks()))
580 .collect::<Vec<_>>();
581
582 let mut nulls_masks_iter = bit_chunks
583 .iter()
584 .map(|(type_id, bit_chunks)| (*type_id, bit_chunks.iter()))
585 .collect::<Vec<_>>();
586
587 let chunks_exact = self.type_ids.chunks_exact(64);
588 let remainder = chunks_exact.remainder();
589
590 let chunks = chunks_exact.map(|type_ids_chunk| {
591 let type_ids_chunk_array = <&[i8; 64]>::try_from(type_ids_chunk).unwrap();
592
593 mask_chunk(type_ids_chunk_array, &mut nulls_masks_iter)
594 });
595
596 let mut buffer = unsafe { MutableBuffer::from_trusted_len_iter(chunks) };
599
600 if !remainder.is_empty() {
601 buffer.push(mask_remainder(remainder, &bit_chunks));
602 }
603
604 BooleanBuffer::new(buffer.into(), 0, self.type_ids.len())
605 }
606
607 fn gather_nulls(&self, nulls: Vec<(i8, NullBuffer)>) -> BooleanBuffer {
609 let one_null = NullBuffer::new_null(1);
610 let one_valid = NullBuffer::new_valid(1);
611
612 let mut logical_nulls_array = [(&one_valid, Mask::Zero); 256];
619
620 for (type_id, nulls) in &nulls {
621 if nulls.null_count() == nulls.len() {
622 logical_nulls_array[*type_id as u8 as usize] = (&one_null, Mask::Zero);
624 } else {
625 logical_nulls_array[*type_id as u8 as usize] = (nulls, Mask::Max);
626 }
627 }
628
629 match &self.offsets {
630 Some(offsets) => {
631 assert_eq!(self.type_ids.len(), offsets.len());
632
633 BooleanBuffer::collect_bool(self.type_ids.len(), |i| unsafe {
634 let type_id = *self.type_ids.get_unchecked(i);
636 let offset = *offsets.get_unchecked(i);
638
639 let (nulls, offset_mask) = &logical_nulls_array[type_id as u8 as usize];
640
641 nulls
647 .inner()
648 .value_unchecked(offset as usize & *offset_mask as usize)
649 })
650 }
651 None => {
652 BooleanBuffer::collect_bool(self.type_ids.len(), |index| unsafe {
653 let type_id = *self.type_ids.get_unchecked(index);
655
656 let (nulls, index_mask) = &logical_nulls_array[type_id as u8 as usize];
657
658 nulls.inner().value_unchecked(index & *index_mask as usize)
664 })
665 }
666 }
667 }
668
669 fn fields_logical_nulls(&self) -> Vec<(i8, NullBuffer)> {
672 self.fields
673 .iter()
674 .enumerate()
675 .filter_map(|(type_id, field)| Some((type_id as i8, field.as_ref()?.logical_nulls()?)))
676 .filter(|(_, nulls)| nulls.null_count() > 0)
677 .collect()
678 }
679}
680
681impl From<ArrayData> for UnionArray {
682 fn from(data: ArrayData) -> Self {
683 let (fields, mode) = match data.data_type() {
684 DataType::Union(fields, mode) => (fields, *mode),
685 d => panic!("UnionArray expected ArrayData with type Union got {d}"),
686 };
687 let (type_ids, offsets) = match mode {
688 UnionMode::Sparse => (
689 ScalarBuffer::new(data.buffers()[0].clone(), data.offset(), data.len()),
690 None,
691 ),
692 UnionMode::Dense => (
693 ScalarBuffer::new(data.buffers()[0].clone(), data.offset(), data.len()),
694 Some(ScalarBuffer::new(
695 data.buffers()[1].clone(),
696 data.offset(),
697 data.len(),
698 )),
699 ),
700 };
701
702 let max_id = fields.iter().map(|(i, _)| i).max().unwrap_or_default() as usize;
703 let mut boxed_fields = vec![None; max_id + 1];
704 for (cd, (field_id, _)) in data.child_data().iter().zip(fields.iter()) {
705 let cd = match mode {
706 UnionMode::Sparse => cd.slice(data.offset(), data.len()),
707 UnionMode::Dense => cd.clone(),
708 };
709 boxed_fields[field_id as usize] = Some(make_array(cd));
710 }
711 Self {
712 data_type: data.data_type().clone(),
713 type_ids,
714 offsets,
715 fields: boxed_fields,
716 }
717 }
718}
719
720impl From<UnionArray> for ArrayData {
721 fn from(array: UnionArray) -> Self {
722 let len = array.len();
723 let f = match &array.data_type {
724 DataType::Union(f, _) => f,
725 _ => unreachable!(),
726 };
727 let buffers = match array.offsets {
728 Some(o) => vec![array.type_ids.into_inner(), o.into_inner()],
729 None => vec![array.type_ids.into_inner()],
730 };
731
732 let child = f
733 .iter()
734 .map(|(i, _)| array.fields[i as usize].as_ref().unwrap().to_data())
735 .collect();
736
737 let builder = ArrayDataBuilder::new(array.data_type)
738 .len(len)
739 .buffers(buffers)
740 .child_data(child);
741 unsafe { builder.build_unchecked() }
742 }
743}
744
745unsafe impl Array for UnionArray {
747 fn as_any(&self) -> &dyn Any {
748 self
749 }
750
751 fn to_data(&self) -> ArrayData {
752 self.clone().into()
753 }
754
755 fn into_data(self) -> ArrayData {
756 self.into()
757 }
758
759 fn data_type(&self) -> &DataType {
760 &self.data_type
761 }
762
763 fn slice(&self, offset: usize, length: usize) -> ArrayRef {
764 Arc::new(self.slice(offset, length))
765 }
766
767 fn len(&self) -> usize {
768 self.type_ids.len()
769 }
770
771 fn is_empty(&self) -> bool {
772 self.type_ids.is_empty()
773 }
774
775 fn shrink_to_fit(&mut self) {
776 self.type_ids.shrink_to_fit();
777 if let Some(offsets) = &mut self.offsets {
778 offsets.shrink_to_fit();
779 }
780 for array in self.fields.iter_mut().flatten() {
781 array.shrink_to_fit();
782 }
783 self.fields.shrink_to_fit();
784 }
785
786 fn offset(&self) -> usize {
787 0
788 }
789
790 fn nulls(&self) -> Option<&NullBuffer> {
791 None
792 }
793
794 fn logical_nulls(&self) -> Option<NullBuffer> {
795 let fields = match self.data_type() {
796 DataType::Union(fields, _) => fields,
797 _ => unreachable!(),
798 };
799
800 if fields.len() <= 1 {
801 return self
802 .fields
803 .iter()
804 .enumerate()
805 .find_map(|(type_id, field_opt)| {
806 field_opt
807 .as_ref()
808 .and_then(|field| field.logical_nulls())
809 .map(|logical_nulls| {
810 if self.is_dense() {
811 self.gather_nulls(vec![(type_id as i8, logical_nulls)])
812 .into()
813 } else {
814 logical_nulls
815 }
816 })
817 });
818 }
819
820 let logical_nulls = self.fields_logical_nulls();
821
822 if logical_nulls.is_empty() {
823 return None;
824 }
825
826 let fully_null_count = logical_nulls
827 .iter()
828 .filter(|(_, nulls)| nulls.null_count() == nulls.len())
829 .count();
830
831 if fully_null_count == fields.len() {
832 if let Some((_, exactly_sized)) = logical_nulls
833 .iter()
834 .find(|(_, nulls)| nulls.len() == self.len())
835 {
836 return Some(exactly_sized.clone());
837 }
838
839 if let Some((_, bigger)) = logical_nulls
840 .iter()
841 .find(|(_, nulls)| nulls.len() > self.len())
842 {
843 return Some(bigger.slice(0, self.len()));
844 }
845
846 return Some(NullBuffer::new_null(self.len()));
847 }
848
849 let boolean_buffer = match &self.offsets {
850 Some(_) => self.gather_nulls(logical_nulls),
851 None => {
852 let gather_relative_cost = if cfg!(target_feature = "avx2") {
860 10
861 } else if cfg!(target_feature = "sse4.1") {
862 3
863 } else if cfg!(target_arch = "x86") || cfg!(target_arch = "x86_64") {
864 2
866 } else {
867 0
871 };
872
873 let strategies = [
874 (SparseStrategy::Gather, gather_relative_cost, true),
875 (
876 SparseStrategy::MaskAllFieldsWithNullsSkipOne,
877 fields.len() - 1,
878 fields.len() == logical_nulls.len(),
879 ),
880 (
881 SparseStrategy::MaskSkipWithoutNulls,
882 logical_nulls.len(),
883 true,
884 ),
885 (
886 SparseStrategy::MaskSkipFullyNull,
887 fields.len() - fully_null_count,
888 true,
889 ),
890 ];
891
892 let (strategy, _, _) = strategies
893 .iter()
894 .filter(|(_, _, applicable)| *applicable)
895 .min_by_key(|(_, cost, _)| cost)
896 .unwrap();
897
898 match strategy {
899 SparseStrategy::Gather => self.gather_nulls(logical_nulls),
900 SparseStrategy::MaskAllFieldsWithNullsSkipOne => {
901 self.mask_sparse_all_with_nulls_skip_one(logical_nulls)
902 }
903 SparseStrategy::MaskSkipWithoutNulls => {
904 self.mask_sparse_skip_without_nulls(logical_nulls)
905 }
906 SparseStrategy::MaskSkipFullyNull => {
907 self.mask_sparse_skip_fully_null(logical_nulls)
908 }
909 }
910 }
911 };
912
913 let null_buffer = NullBuffer::from(boolean_buffer);
914
915 if null_buffer.null_count() > 0 {
916 Some(null_buffer)
917 } else {
918 None
919 }
920 }
921
922 fn is_nullable(&self) -> bool {
923 self.fields
924 .iter()
925 .flatten()
926 .any(|field| field.is_nullable())
927 }
928
929 fn get_buffer_memory_size(&self) -> usize {
930 let mut sum = self.type_ids.inner().capacity();
931 if let Some(o) = self.offsets.as_ref() {
932 sum += o.inner().capacity()
933 }
934 self.fields
935 .iter()
936 .flat_map(|x| x.as_ref().map(|x| x.get_buffer_memory_size()))
937 .sum::<usize>()
938 + sum
939 }
940
941 fn get_array_memory_size(&self) -> usize {
942 let mut sum = self.type_ids.inner().capacity();
943 if let Some(o) = self.offsets.as_ref() {
944 sum += o.inner().capacity()
945 }
946 std::mem::size_of::<Self>()
947 + self
948 .fields
949 .iter()
950 .flat_map(|x| x.as_ref().map(|x| x.get_array_memory_size()))
951 .sum::<usize>()
952 + sum
953 }
954}
955
956impl std::fmt::Debug for UnionArray {
957 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
958 let header = if self.is_dense() {
959 "UnionArray(Dense)\n["
960 } else {
961 "UnionArray(Sparse)\n["
962 };
963 writeln!(f, "{header}")?;
964
965 writeln!(f, "-- type id buffer:")?;
966 writeln!(f, "{:?}", self.type_ids)?;
967
968 if let Some(offsets) = &self.offsets {
969 writeln!(f, "-- offsets buffer:")?;
970 writeln!(f, "{offsets:?}")?;
971 }
972
973 let fields = match self.data_type() {
974 DataType::Union(fields, _) => fields,
975 _ => unreachable!(),
976 };
977
978 for (type_id, field) in fields.iter() {
979 let child = self.child(type_id);
980 writeln!(
981 f,
982 "-- child {}: \"{}\" ({:?})",
983 type_id,
984 field.name(),
985 field.data_type()
986 )?;
987 std::fmt::Debug::fmt(child, f)?;
988 writeln!(f)?;
989 }
990 writeln!(f, "]")
991 }
992}
993
994enum SparseStrategy {
999 Gather,
1001 MaskAllFieldsWithNullsSkipOne,
1003 MaskSkipWithoutNulls,
1005 MaskSkipFullyNull,
1007}
1008
1009#[derive(Copy, Clone)]
1010#[repr(usize)]
1011enum Mask {
1012 Zero = 0,
1013 #[allow(clippy::enum_clike_unportable_variant)]
1015 Max = usize::MAX,
1016}
1017
1018fn selection_mask(type_ids_chunk: &[i8], type_id: i8) -> u64 {
1019 type_ids_chunk
1020 .iter()
1021 .copied()
1022 .enumerate()
1023 .fold(0, |packed, (bit_idx, v)| {
1024 packed | (((v == type_id) as u64) << bit_idx)
1025 })
1026}
1027
1028fn without_nulls_selected(type_ids_chunk: &[i8], without_nulls_ids: &[i8]) -> u64 {
1030 without_nulls_ids
1031 .iter()
1032 .fold(0, |fully_valid_selected, field_type_id| {
1033 fully_valid_selected | selection_mask(type_ids_chunk, *field_type_id)
1034 })
1035}
1036
1037#[cfg(test)]
1038mod tests {
1039 use super::*;
1040 use std::collections::HashSet;
1041
1042 use crate::array::Int8Type;
1043 use crate::builder::UnionBuilder;
1044 use crate::cast::AsArray;
1045 use crate::types::{Float32Type, Float64Type, Int32Type, Int64Type};
1046 use crate::{Float64Array, Int32Array, Int64Array, StringArray};
1047 use crate::{Int8Array, RecordBatch};
1048 use arrow_buffer::Buffer;
1049 use arrow_schema::{Field, Schema};
1050
1051 #[test]
1052 fn test_dense_i32() {
1053 let mut builder = UnionBuilder::new_dense();
1054 builder.append::<Int32Type>("a", 1).unwrap();
1055 builder.append::<Int32Type>("b", 2).unwrap();
1056 builder.append::<Int32Type>("c", 3).unwrap();
1057 builder.append::<Int32Type>("a", 4).unwrap();
1058 builder.append::<Int32Type>("c", 5).unwrap();
1059 builder.append::<Int32Type>("a", 6).unwrap();
1060 builder.append::<Int32Type>("b", 7).unwrap();
1061 let union = builder.build().unwrap();
1062
1063 let expected_type_ids = vec![0_i8, 1, 2, 0, 2, 0, 1];
1064 let expected_offsets = vec![0_i32, 0, 0, 1, 1, 2, 1];
1065 let expected_array_values = [1_i32, 2, 3, 4, 5, 6, 7];
1066
1067 assert_eq!(*union.type_ids(), expected_type_ids);
1069 for (i, id) in expected_type_ids.iter().enumerate() {
1070 assert_eq!(id, &union.type_id(i));
1071 }
1072
1073 assert_eq!(*union.offsets().unwrap(), expected_offsets);
1075 for (i, id) in expected_offsets.iter().enumerate() {
1076 assert_eq!(union.value_offset(i), *id as usize);
1077 }
1078
1079 assert_eq!(
1081 *union.child(0).as_primitive::<Int32Type>().values(),
1082 [1_i32, 4, 6]
1083 );
1084 assert_eq!(
1085 *union.child(1).as_primitive::<Int32Type>().values(),
1086 [2_i32, 7]
1087 );
1088 assert_eq!(
1089 *union.child(2).as_primitive::<Int32Type>().values(),
1090 [3_i32, 5]
1091 );
1092
1093 assert_eq!(expected_array_values.len(), union.len());
1094 for (i, expected_value) in expected_array_values.iter().enumerate() {
1095 assert!(!union.is_null(i));
1096 let slot = union.value(i);
1097 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1098 assert_eq!(slot.len(), 1);
1099 let value = slot.value(0);
1100 assert_eq!(expected_value, &value);
1101 }
1102 }
1103
1104 #[test]
1105 fn slice_union_array_single_field() {
1106 let union_array = {
1109 let mut builder = UnionBuilder::new_dense();
1110 builder.append::<Int32Type>("a", 1).unwrap();
1111 builder.append_null::<Int32Type>("a").unwrap();
1112 builder.append::<Int32Type>("a", 3).unwrap();
1113 builder.append_null::<Int32Type>("a").unwrap();
1114 builder.append::<Int32Type>("a", 4).unwrap();
1115 builder.build().unwrap()
1116 };
1117
1118 let union_slice = union_array.slice(1, 3);
1120 let logical_nulls = union_slice.logical_nulls().unwrap();
1121
1122 assert_eq!(logical_nulls.len(), 3);
1123 assert!(logical_nulls.is_null(0));
1124 assert!(logical_nulls.is_valid(1));
1125 assert!(logical_nulls.is_null(2));
1126 }
1127
1128 #[test]
1129 #[cfg_attr(miri, ignore)]
1130 fn test_dense_i32_large() {
1131 let mut builder = UnionBuilder::new_dense();
1132
1133 let expected_type_ids = vec![0_i8; 1024];
1134 let expected_offsets: Vec<_> = (0..1024).collect();
1135 let expected_array_values: Vec<_> = (1..=1024).collect();
1136
1137 expected_array_values
1138 .iter()
1139 .for_each(|v| builder.append::<Int32Type>("a", *v).unwrap());
1140
1141 let union = builder.build().unwrap();
1142
1143 assert_eq!(*union.type_ids(), expected_type_ids);
1145 for (i, id) in expected_type_ids.iter().enumerate() {
1146 assert_eq!(id, &union.type_id(i));
1147 }
1148
1149 assert_eq!(*union.offsets().unwrap(), expected_offsets);
1151 for (i, id) in expected_offsets.iter().enumerate() {
1152 assert_eq!(union.value_offset(i), *id as usize);
1153 }
1154
1155 for (i, expected_value) in expected_array_values.iter().enumerate() {
1156 assert!(!union.is_null(i));
1157 let slot = union.value(i);
1158 let slot = slot.as_primitive::<Int32Type>();
1159 assert_eq!(slot.len(), 1);
1160 let value = slot.value(0);
1161 assert_eq!(expected_value, &value);
1162 }
1163 }
1164
1165 #[test]
1166 fn test_dense_mixed() {
1167 let mut builder = UnionBuilder::new_dense();
1168 builder.append::<Int32Type>("a", 1).unwrap();
1169 builder.append::<Int64Type>("c", 3).unwrap();
1170 builder.append::<Int32Type>("a", 4).unwrap();
1171 builder.append::<Int64Type>("c", 5).unwrap();
1172 builder.append::<Int32Type>("a", 6).unwrap();
1173 let union = builder.build().unwrap();
1174
1175 assert_eq!(5, union.len());
1176 for i in 0..union.len() {
1177 let slot = union.value(i);
1178 assert!(!union.is_null(i));
1179 match i {
1180 0 => {
1181 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1182 assert_eq!(slot.len(), 1);
1183 let value = slot.value(0);
1184 assert_eq!(1_i32, value);
1185 }
1186 1 => {
1187 let slot = slot.as_any().downcast_ref::<Int64Array>().unwrap();
1188 assert_eq!(slot.len(), 1);
1189 let value = slot.value(0);
1190 assert_eq!(3_i64, value);
1191 }
1192 2 => {
1193 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1194 assert_eq!(slot.len(), 1);
1195 let value = slot.value(0);
1196 assert_eq!(4_i32, value);
1197 }
1198 3 => {
1199 let slot = slot.as_any().downcast_ref::<Int64Array>().unwrap();
1200 assert_eq!(slot.len(), 1);
1201 let value = slot.value(0);
1202 assert_eq!(5_i64, value);
1203 }
1204 4 => {
1205 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1206 assert_eq!(slot.len(), 1);
1207 let value = slot.value(0);
1208 assert_eq!(6_i32, value);
1209 }
1210 _ => unreachable!(),
1211 }
1212 }
1213 }
1214
1215 #[test]
1216 fn test_dense_mixed_with_nulls() {
1217 let mut builder = UnionBuilder::new_dense();
1218 builder.append::<Int32Type>("a", 1).unwrap();
1219 builder.append::<Int64Type>("c", 3).unwrap();
1220 builder.append::<Int32Type>("a", 10).unwrap();
1221 builder.append_null::<Int32Type>("a").unwrap();
1222 builder.append::<Int32Type>("a", 6).unwrap();
1223 let union = builder.build().unwrap();
1224
1225 assert_eq!(5, union.len());
1226 for i in 0..union.len() {
1227 let slot = union.value(i);
1228 match i {
1229 0 => {
1230 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1231 assert!(!slot.is_null(0));
1232 assert_eq!(slot.len(), 1);
1233 let value = slot.value(0);
1234 assert_eq!(1_i32, value);
1235 }
1236 1 => {
1237 let slot = slot.as_any().downcast_ref::<Int64Array>().unwrap();
1238 assert!(!slot.is_null(0));
1239 assert_eq!(slot.len(), 1);
1240 let value = slot.value(0);
1241 assert_eq!(3_i64, value);
1242 }
1243 2 => {
1244 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1245 assert!(!slot.is_null(0));
1246 assert_eq!(slot.len(), 1);
1247 let value = slot.value(0);
1248 assert_eq!(10_i32, value);
1249 }
1250 3 => assert!(slot.is_null(0)),
1251 4 => {
1252 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1253 assert!(!slot.is_null(0));
1254 assert_eq!(slot.len(), 1);
1255 let value = slot.value(0);
1256 assert_eq!(6_i32, value);
1257 }
1258 _ => unreachable!(),
1259 }
1260 }
1261 }
1262
1263 #[test]
1264 fn test_dense_mixed_with_nulls_and_offset() {
1265 let mut builder = UnionBuilder::new_dense();
1266 builder.append::<Int32Type>("a", 1).unwrap();
1267 builder.append::<Int64Type>("c", 3).unwrap();
1268 builder.append::<Int32Type>("a", 10).unwrap();
1269 builder.append_null::<Int32Type>("a").unwrap();
1270 builder.append::<Int32Type>("a", 6).unwrap();
1271 let union = builder.build().unwrap();
1272
1273 let slice = union.slice(2, 3);
1274 let new_union = slice.as_any().downcast_ref::<UnionArray>().unwrap();
1275
1276 assert_eq!(3, new_union.len());
1277 for i in 0..new_union.len() {
1278 let slot = new_union.value(i);
1279 match i {
1280 0 => {
1281 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1282 assert!(!slot.is_null(0));
1283 assert_eq!(slot.len(), 1);
1284 let value = slot.value(0);
1285 assert_eq!(10_i32, value);
1286 }
1287 1 => assert!(slot.is_null(0)),
1288 2 => {
1289 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1290 assert!(!slot.is_null(0));
1291 assert_eq!(slot.len(), 1);
1292 let value = slot.value(0);
1293 assert_eq!(6_i32, value);
1294 }
1295 _ => unreachable!(),
1296 }
1297 }
1298 }
1299
1300 #[test]
1301 fn test_dense_mixed_with_str() {
1302 let string_array = StringArray::from(vec!["foo", "bar", "baz"]);
1303 let int_array = Int32Array::from(vec![5, 6]);
1304 let float_array = Float64Array::from(vec![10.0]);
1305
1306 let type_ids = [1, 0, 0, 2, 0, 1].into_iter().collect::<ScalarBuffer<i8>>();
1307 let offsets = [0, 0, 1, 0, 2, 1]
1308 .into_iter()
1309 .collect::<ScalarBuffer<i32>>();
1310
1311 let fields = [
1312 (0, Arc::new(Field::new("A", DataType::Utf8, false))),
1313 (1, Arc::new(Field::new("B", DataType::Int32, false))),
1314 (2, Arc::new(Field::new("C", DataType::Float64, false))),
1315 ]
1316 .into_iter()
1317 .collect::<UnionFields>();
1318 let children = [
1319 Arc::new(string_array) as Arc<dyn Array>,
1320 Arc::new(int_array),
1321 Arc::new(float_array),
1322 ]
1323 .into_iter()
1324 .collect();
1325 let array =
1326 UnionArray::try_new(fields, type_ids.clone(), Some(offsets.clone()), children).unwrap();
1327
1328 assert_eq!(*array.type_ids(), type_ids);
1330 for (i, id) in type_ids.iter().enumerate() {
1331 assert_eq!(id, &array.type_id(i));
1332 }
1333
1334 assert_eq!(*array.offsets().unwrap(), offsets);
1336 for (i, id) in offsets.iter().enumerate() {
1337 assert_eq!(*id as usize, array.value_offset(i));
1338 }
1339
1340 assert_eq!(6, array.len());
1342
1343 let slot = array.value(0);
1344 let value = slot.as_any().downcast_ref::<Int32Array>().unwrap().value(0);
1345 assert_eq!(5, value);
1346
1347 let slot = array.value(1);
1348 let value = slot
1349 .as_any()
1350 .downcast_ref::<StringArray>()
1351 .unwrap()
1352 .value(0);
1353 assert_eq!("foo", value);
1354
1355 let slot = array.value(2);
1356 let value = slot
1357 .as_any()
1358 .downcast_ref::<StringArray>()
1359 .unwrap()
1360 .value(0);
1361 assert_eq!("bar", value);
1362
1363 let slot = array.value(3);
1364 let value = slot
1365 .as_any()
1366 .downcast_ref::<Float64Array>()
1367 .unwrap()
1368 .value(0);
1369 assert_eq!(10.0, value);
1370
1371 let slot = array.value(4);
1372 let value = slot
1373 .as_any()
1374 .downcast_ref::<StringArray>()
1375 .unwrap()
1376 .value(0);
1377 assert_eq!("baz", value);
1378
1379 let slot = array.value(5);
1380 let value = slot.as_any().downcast_ref::<Int32Array>().unwrap().value(0);
1381 assert_eq!(6, value);
1382 }
1383
1384 #[test]
1385 fn test_sparse_i32() {
1386 let mut builder = UnionBuilder::new_sparse();
1387 builder.append::<Int32Type>("a", 1).unwrap();
1388 builder.append::<Int32Type>("b", 2).unwrap();
1389 builder.append::<Int32Type>("c", 3).unwrap();
1390 builder.append::<Int32Type>("a", 4).unwrap();
1391 builder.append::<Int32Type>("c", 5).unwrap();
1392 builder.append::<Int32Type>("a", 6).unwrap();
1393 builder.append::<Int32Type>("b", 7).unwrap();
1394 let union = builder.build().unwrap();
1395
1396 let expected_type_ids = vec![0_i8, 1, 2, 0, 2, 0, 1];
1397 let expected_array_values = [1_i32, 2, 3, 4, 5, 6, 7];
1398
1399 assert_eq!(*union.type_ids(), expected_type_ids);
1401 for (i, id) in expected_type_ids.iter().enumerate() {
1402 assert_eq!(id, &union.type_id(i));
1403 }
1404
1405 assert!(union.offsets().is_none());
1407
1408 assert_eq!(
1410 *union.child(0).as_primitive::<Int32Type>().values(),
1411 [1_i32, 0, 0, 4, 0, 6, 0],
1412 );
1413 assert_eq!(
1414 *union.child(1).as_primitive::<Int32Type>().values(),
1415 [0_i32, 2_i32, 0, 0, 0, 0, 7]
1416 );
1417 assert_eq!(
1418 *union.child(2).as_primitive::<Int32Type>().values(),
1419 [0_i32, 0, 3_i32, 0, 5, 0, 0]
1420 );
1421
1422 assert_eq!(expected_array_values.len(), union.len());
1423 for (i, expected_value) in expected_array_values.iter().enumerate() {
1424 assert!(!union.is_null(i));
1425 let slot = union.value(i);
1426 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1427 assert_eq!(slot.len(), 1);
1428 let value = slot.value(0);
1429 assert_eq!(expected_value, &value);
1430 }
1431 }
1432
1433 #[test]
1434 fn test_sparse_mixed() {
1435 let mut builder = UnionBuilder::new_sparse();
1436 builder.append::<Int32Type>("a", 1).unwrap();
1437 builder.append::<Float64Type>("c", 3.0).unwrap();
1438 builder.append::<Int32Type>("a", 4).unwrap();
1439 builder.append::<Float64Type>("c", 5.0).unwrap();
1440 builder.append::<Int32Type>("a", 6).unwrap();
1441 let union = builder.build().unwrap();
1442
1443 let expected_type_ids = vec![0_i8, 1, 0, 1, 0];
1444
1445 assert_eq!(*union.type_ids(), expected_type_ids);
1447 for (i, id) in expected_type_ids.iter().enumerate() {
1448 assert_eq!(id, &union.type_id(i));
1449 }
1450
1451 assert!(union.offsets().is_none());
1453
1454 for i in 0..union.len() {
1455 let slot = union.value(i);
1456 assert!(!union.is_null(i));
1457 match i {
1458 0 => {
1459 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1460 assert_eq!(slot.len(), 1);
1461 let value = slot.value(0);
1462 assert_eq!(1_i32, value);
1463 }
1464 1 => {
1465 let slot = slot.as_any().downcast_ref::<Float64Array>().unwrap();
1466 assert_eq!(slot.len(), 1);
1467 let value = slot.value(0);
1468 assert_eq!(value, 3_f64);
1469 }
1470 2 => {
1471 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1472 assert_eq!(slot.len(), 1);
1473 let value = slot.value(0);
1474 assert_eq!(4_i32, value);
1475 }
1476 3 => {
1477 let slot = slot.as_any().downcast_ref::<Float64Array>().unwrap();
1478 assert_eq!(slot.len(), 1);
1479 let value = slot.value(0);
1480 assert_eq!(5_f64, value);
1481 }
1482 4 => {
1483 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1484 assert_eq!(slot.len(), 1);
1485 let value = slot.value(0);
1486 assert_eq!(6_i32, value);
1487 }
1488 _ => unreachable!(),
1489 }
1490 }
1491 }
1492
1493 #[test]
1494 fn test_sparse_mixed_with_nulls() {
1495 let mut builder = UnionBuilder::new_sparse();
1496 builder.append::<Int32Type>("a", 1).unwrap();
1497 builder.append_null::<Int32Type>("a").unwrap();
1498 builder.append::<Float64Type>("c", 3.0).unwrap();
1499 builder.append::<Int32Type>("a", 4).unwrap();
1500 let union = builder.build().unwrap();
1501
1502 let expected_type_ids = vec![0_i8, 0, 1, 0];
1503
1504 assert_eq!(*union.type_ids(), expected_type_ids);
1506 for (i, id) in expected_type_ids.iter().enumerate() {
1507 assert_eq!(id, &union.type_id(i));
1508 }
1509
1510 assert!(union.offsets().is_none());
1512
1513 for i in 0..union.len() {
1514 let slot = union.value(i);
1515 match i {
1516 0 => {
1517 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1518 assert!(!slot.is_null(0));
1519 assert_eq!(slot.len(), 1);
1520 let value = slot.value(0);
1521 assert_eq!(1_i32, value);
1522 }
1523 1 => assert!(slot.is_null(0)),
1524 2 => {
1525 let slot = slot.as_any().downcast_ref::<Float64Array>().unwrap();
1526 assert!(!slot.is_null(0));
1527 assert_eq!(slot.len(), 1);
1528 let value = slot.value(0);
1529 assert_eq!(value, 3_f64);
1530 }
1531 3 => {
1532 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1533 assert!(!slot.is_null(0));
1534 assert_eq!(slot.len(), 1);
1535 let value = slot.value(0);
1536 assert_eq!(4_i32, value);
1537 }
1538 _ => unreachable!(),
1539 }
1540 }
1541 }
1542
1543 #[test]
1544 fn test_sparse_mixed_with_nulls_and_offset() {
1545 let mut builder = UnionBuilder::new_sparse();
1546 builder.append::<Int32Type>("a", 1).unwrap();
1547 builder.append_null::<Int32Type>("a").unwrap();
1548 builder.append::<Float64Type>("c", 3.0).unwrap();
1549 builder.append_null::<Float64Type>("c").unwrap();
1550 builder.append::<Int32Type>("a", 4).unwrap();
1551 let union = builder.build().unwrap();
1552
1553 let slice = union.slice(1, 4);
1554 let new_union = slice.as_any().downcast_ref::<UnionArray>().unwrap();
1555
1556 assert_eq!(4, new_union.len());
1557 for i in 0..new_union.len() {
1558 let slot = new_union.value(i);
1559 match i {
1560 0 => assert!(slot.is_null(0)),
1561 1 => {
1562 let slot = slot.as_primitive::<Float64Type>();
1563 assert!(!slot.is_null(0));
1564 assert_eq!(slot.len(), 1);
1565 let value = slot.value(0);
1566 assert_eq!(value, 3_f64);
1567 }
1568 2 => assert!(slot.is_null(0)),
1569 3 => {
1570 let slot = slot.as_primitive::<Int32Type>();
1571 assert!(!slot.is_null(0));
1572 assert_eq!(slot.len(), 1);
1573 let value = slot.value(0);
1574 assert_eq!(4_i32, value);
1575 }
1576 _ => unreachable!(),
1577 }
1578 }
1579 }
1580
1581 fn test_union_validity(union_array: &UnionArray) {
1582 assert_eq!(union_array.null_count(), 0);
1583
1584 for i in 0..union_array.len() {
1585 assert!(!union_array.is_null(i));
1586 assert!(union_array.is_valid(i));
1587 }
1588 }
1589
1590 #[test]
1591 fn test_union_array_validity() {
1592 let mut builder = UnionBuilder::new_sparse();
1593 builder.append::<Int32Type>("a", 1).unwrap();
1594 builder.append_null::<Int32Type>("a").unwrap();
1595 builder.append::<Float64Type>("c", 3.0).unwrap();
1596 builder.append_null::<Float64Type>("c").unwrap();
1597 builder.append::<Int32Type>("a", 4).unwrap();
1598 let union = builder.build().unwrap();
1599
1600 test_union_validity(&union);
1601
1602 let mut builder = UnionBuilder::new_dense();
1603 builder.append::<Int32Type>("a", 1).unwrap();
1604 builder.append_null::<Int32Type>("a").unwrap();
1605 builder.append::<Float64Type>("c", 3.0).unwrap();
1606 builder.append_null::<Float64Type>("c").unwrap();
1607 builder.append::<Int32Type>("a", 4).unwrap();
1608 let union = builder.build().unwrap();
1609
1610 test_union_validity(&union);
1611 }
1612
1613 #[test]
1614 fn test_type_check() {
1615 let mut builder = UnionBuilder::new_sparse();
1616 builder.append::<Float32Type>("a", 1.0).unwrap();
1617 let err = builder.append::<Int32Type>("a", 1).unwrap_err().to_string();
1618 assert!(
1619 err.contains(
1620 "Attempt to write col \"a\" with type Int32 doesn't match existing type Float32"
1621 ),
1622 "{}",
1623 err
1624 );
1625 }
1626
1627 #[test]
1628 fn slice_union_array() {
1629 fn create_union(mut builder: UnionBuilder) -> UnionArray {
1631 builder.append::<Int32Type>("a", 1).unwrap();
1632 builder.append_null::<Int32Type>("a").unwrap();
1633 builder.append::<Float64Type>("c", 3.0).unwrap();
1634 builder.append_null::<Float64Type>("c").unwrap();
1635 builder.append::<Int32Type>("a", 4).unwrap();
1636 builder.build().unwrap()
1637 }
1638
1639 fn create_batch(union: UnionArray) -> RecordBatch {
1640 let schema = Schema::new(vec![Field::new(
1641 "struct_array",
1642 union.data_type().clone(),
1643 true,
1644 )]);
1645
1646 RecordBatch::try_new(Arc::new(schema), vec![Arc::new(union)]).unwrap()
1647 }
1648
1649 fn test_slice_union(record_batch_slice: RecordBatch) {
1650 let union_slice = record_batch_slice
1651 .column(0)
1652 .as_any()
1653 .downcast_ref::<UnionArray>()
1654 .unwrap();
1655
1656 assert_eq!(union_slice.type_id(0), 0);
1657 assert_eq!(union_slice.type_id(1), 1);
1658 assert_eq!(union_slice.type_id(2), 1);
1659
1660 let slot = union_slice.value(0);
1661 let array = slot.as_primitive::<Int32Type>();
1662 assert_eq!(array.len(), 1);
1663 assert!(array.is_null(0));
1664
1665 let slot = union_slice.value(1);
1666 let array = slot.as_primitive::<Float64Type>();
1667 assert_eq!(array.len(), 1);
1668 assert!(array.is_valid(0));
1669 assert_eq!(array.value(0), 3.0);
1670
1671 let slot = union_slice.value(2);
1672 let array = slot.as_primitive::<Float64Type>();
1673 assert_eq!(array.len(), 1);
1674 assert!(array.is_null(0));
1675 }
1676
1677 let builder = UnionBuilder::new_sparse();
1679 let record_batch = create_batch(create_union(builder));
1680 let record_batch_slice = record_batch.slice(1, 3);
1682 test_slice_union(record_batch_slice);
1683
1684 let builder = UnionBuilder::new_dense();
1686 let record_batch = create_batch(create_union(builder));
1687 let record_batch_slice = record_batch.slice(1, 3);
1689 test_slice_union(record_batch_slice);
1690 }
1691
1692 #[test]
1693 fn test_union_from_sliced_array_data() {
1694 for mode in [UnionMode::Sparse, UnionMode::Dense] {
1695 let fields = UnionFields::try_new(
1696 [3, 7],
1697 [
1698 Field::new("ints", DataType::Int32, false),
1699 Field::new("floats", DataType::Float64, false),
1700 ],
1701 )
1702 .unwrap();
1703 let offsets = (mode == UnionMode::Dense).then(|| vec![0, 1, 2, 3].into());
1704 let array = UnionArray::try_new(
1705 fields,
1706 vec![3, 7, 3, 7].into(),
1707 offsets,
1708 vec![
1709 Arc::new(Int32Array::from(vec![10, 20, 30, 40])),
1710 Arc::new(Float64Array::from(vec![1.0, 2.0, 3.0, 4.0])),
1711 ],
1712 )
1713 .unwrap();
1714 for (offset, len) in [(1, 2), (0, 2), (4, 0), (0, 4)] {
1715 let expected = array.slice(offset, len);
1716 let actual = make_array(array.to_data().slice(offset, len));
1717 let actual = actual.as_any().downcast_ref::<UnionArray>().unwrap();
1718 for i in 0..len {
1719 assert_eq!(actual.value(i).to_data(), expected.value(i).to_data());
1720 }
1721 assert_eq!(actual.to_data(), expected.to_data());
1722 }
1723 }
1724 }
1725
1726 #[test]
1727 fn test_sparse_union_from_sliced_array_data_logical_nulls() {
1728 let child = Int32Array::from(vec![Some(10), None, Some(30)]);
1729 let fields =
1730 UnionFields::try_new([0], [Field::new("ints", DataType::Int32, true)]).unwrap();
1731 let array =
1732 UnionArray::try_new(fields, vec![0, 0, 0].into(), None, vec![Arc::new(child)]).unwrap();
1733 for (offset, len) in [(0, 1), (1, 1), (2, 1), (3, 0)] {
1734 let expected = array.slice(offset, len);
1735 let actual = make_array(array.to_data().slice(offset, len));
1736 assert_eq!(actual.logical_nulls(), expected.logical_nulls());
1737 assert_eq!(actual.to_data(), expected.to_data());
1738 }
1739 }
1740
1741 #[test]
1742 fn test_custom_type_ids() {
1743 let data_type = DataType::Union(
1744 UnionFields::try_new(
1745 vec![8, 4, 9],
1746 vec![
1747 Field::new("strings", DataType::Utf8, false),
1748 Field::new("integers", DataType::Int32, false),
1749 Field::new("floats", DataType::Float64, false),
1750 ],
1751 )
1752 .unwrap(),
1753 UnionMode::Dense,
1754 );
1755
1756 let string_array = StringArray::from(vec!["foo", "bar", "baz"]);
1757 let int_array = Int32Array::from(vec![5, 6, 4]);
1758 let float_array = Float64Array::from(vec![10.0]);
1759
1760 let type_ids = Buffer::from_vec(vec![4_i8, 8, 4, 8, 9, 4, 8]);
1761 let value_offsets = Buffer::from_vec(vec![0_i32, 0, 1, 1, 0, 2, 2]);
1762
1763 let data = ArrayData::builder(data_type)
1764 .len(7)
1765 .buffers(vec![type_ids, value_offsets])
1766 .child_data(vec![
1767 string_array.into_data(),
1768 int_array.into_data(),
1769 float_array.into_data(),
1770 ])
1771 .build()
1772 .unwrap();
1773
1774 let array = UnionArray::from(data);
1775
1776 let v = array.value(0);
1777 assert_eq!(v.data_type(), &DataType::Int32);
1778 assert_eq!(v.len(), 1);
1779 assert_eq!(v.as_primitive::<Int32Type>().value(0), 5);
1780
1781 let v = array.value(1);
1782 assert_eq!(v.data_type(), &DataType::Utf8);
1783 assert_eq!(v.len(), 1);
1784 assert_eq!(v.as_string::<i32>().value(0), "foo");
1785
1786 let v = array.value(2);
1787 assert_eq!(v.data_type(), &DataType::Int32);
1788 assert_eq!(v.len(), 1);
1789 assert_eq!(v.as_primitive::<Int32Type>().value(0), 6);
1790
1791 let v = array.value(3);
1792 assert_eq!(v.data_type(), &DataType::Utf8);
1793 assert_eq!(v.len(), 1);
1794 assert_eq!(v.as_string::<i32>().value(0), "bar");
1795
1796 let v = array.value(4);
1797 assert_eq!(v.data_type(), &DataType::Float64);
1798 assert_eq!(v.len(), 1);
1799 assert_eq!(v.as_primitive::<Float64Type>().value(0), 10.0);
1800
1801 let v = array.value(5);
1802 assert_eq!(v.data_type(), &DataType::Int32);
1803 assert_eq!(v.len(), 1);
1804 assert_eq!(v.as_primitive::<Int32Type>().value(0), 4);
1805
1806 let v = array.value(6);
1807 assert_eq!(v.data_type(), &DataType::Utf8);
1808 assert_eq!(v.len(), 1);
1809 assert_eq!(v.as_string::<i32>().value(0), "baz");
1810 }
1811
1812 #[test]
1813 fn into_parts() {
1814 let mut builder = UnionBuilder::new_dense();
1815 builder.append::<Int32Type>("a", 1).unwrap();
1816 builder.append::<Int8Type>("b", 2).unwrap();
1817 builder.append::<Int32Type>("a", 3).unwrap();
1818 let dense_union = builder.build().unwrap();
1819
1820 let field = [
1821 &Arc::new(Field::new("a", DataType::Int32, false)),
1822 &Arc::new(Field::new("b", DataType::Int8, false)),
1823 ];
1824 let (union_fields, type_ids, offsets, children) = dense_union.into_parts();
1825 assert_eq!(
1826 union_fields
1827 .iter()
1828 .map(|(_, field)| field)
1829 .collect::<Vec<_>>(),
1830 field
1831 );
1832 assert_eq!(type_ids, [0, 1, 0]);
1833 assert!(offsets.is_some());
1834 assert_eq!(offsets.as_ref().unwrap(), &[0, 0, 1]);
1835
1836 let result = UnionArray::try_new(union_fields, type_ids, offsets, children);
1837 assert!(result.is_ok());
1838 assert_eq!(result.unwrap().len(), 3);
1839
1840 let mut builder = UnionBuilder::new_sparse();
1841 builder.append::<Int32Type>("a", 1).unwrap();
1842 builder.append::<Int8Type>("b", 2).unwrap();
1843 builder.append::<Int32Type>("a", 3).unwrap();
1844 let sparse_union = builder.build().unwrap();
1845
1846 let (union_fields, type_ids, offsets, children) = sparse_union.into_parts();
1847 assert_eq!(type_ids, [0, 1, 0]);
1848 assert!(offsets.is_none());
1849
1850 let result = UnionArray::try_new(union_fields, type_ids, offsets, children);
1851 assert!(result.is_ok());
1852 assert_eq!(result.unwrap().len(), 3);
1853 }
1854
1855 #[test]
1856 fn into_parts_custom_type_ids() {
1857 let set_field_type_ids: [i8; 3] = [8, 4, 9];
1858 let data_type = DataType::Union(
1859 UnionFields::try_new(
1860 set_field_type_ids,
1861 [
1862 Field::new("strings", DataType::Utf8, false),
1863 Field::new("integers", DataType::Int32, false),
1864 Field::new("floats", DataType::Float64, false),
1865 ],
1866 )
1867 .unwrap(),
1868 UnionMode::Dense,
1869 );
1870 let string_array = StringArray::from(vec!["foo", "bar", "baz"]);
1871 let int_array = Int32Array::from(vec![5, 6, 4]);
1872 let float_array = Float64Array::from(vec![10.0]);
1873 let type_ids = Buffer::from_vec(vec![4_i8, 8, 4, 8, 9, 4, 8]);
1874 let value_offsets = Buffer::from_vec(vec![0_i32, 0, 1, 1, 0, 2, 2]);
1875 let data = ArrayData::builder(data_type)
1876 .len(7)
1877 .buffers(vec![type_ids, value_offsets])
1878 .child_data(vec![
1879 string_array.into_data(),
1880 int_array.into_data(),
1881 float_array.into_data(),
1882 ])
1883 .build()
1884 .unwrap();
1885 let array = UnionArray::from(data);
1886
1887 let (union_fields, type_ids, offsets, children) = array.into_parts();
1888 assert_eq!(
1889 type_ids.iter().collect::<HashSet<_>>(),
1890 set_field_type_ids.iter().collect::<HashSet<_>>()
1891 );
1892 let result = UnionArray::try_new(union_fields, type_ids, offsets, children);
1893 assert!(result.is_ok());
1894 let array = result.unwrap();
1895 assert_eq!(array.len(), 7);
1896 }
1897
1898 #[test]
1899 fn test_invalid() {
1900 let fields = UnionFields::try_new(
1901 [3, 2],
1902 [
1903 Field::new("a", DataType::Utf8, false),
1904 Field::new("b", DataType::Utf8, false),
1905 ],
1906 )
1907 .unwrap();
1908 let children = vec![
1909 Arc::new(StringArray::from_iter_values(["a", "b"])) as _,
1910 Arc::new(StringArray::from_iter_values(["c", "d"])) as _,
1911 ];
1912
1913 let type_ids = vec![3, 3, 2].into();
1914 let err =
1915 UnionArray::try_new(fields.clone(), type_ids, None, children.clone()).unwrap_err();
1916 assert_eq!(
1917 err.to_string(),
1918 "Invalid argument error: Sparse union child arrays must be equal in length to the length of the union"
1919 );
1920
1921 let type_ids = vec![1, 2].into();
1922 let err =
1923 UnionArray::try_new(fields.clone(), type_ids, None, children.clone()).unwrap_err();
1924 assert_eq!(
1925 err.to_string(),
1926 "Invalid argument error: Type Ids values must match one of the field type ids"
1927 );
1928
1929 let type_ids = vec![7, 2].into();
1930 let err = UnionArray::try_new(fields.clone(), type_ids, None, children).unwrap_err();
1931 assert_eq!(
1932 err.to_string(),
1933 "Invalid argument error: Type Ids values must match one of the field type ids"
1934 );
1935
1936 let children = vec![
1937 Arc::new(StringArray::from_iter_values(["a", "b"])) as _,
1938 Arc::new(StringArray::from_iter_values(["c"])) as _,
1939 ];
1940 let type_ids = ScalarBuffer::from(vec![3_i8, 3, 2]);
1941 let offsets = Some(vec![0, 1, 0].into());
1942 UnionArray::try_new(fields.clone(), type_ids.clone(), offsets, children.clone()).unwrap();
1943
1944 let offsets = Some(vec![0, 1, 1].into());
1945 let err = UnionArray::try_new(fields.clone(), type_ids.clone(), offsets, children.clone())
1946 .unwrap_err();
1947
1948 assert_eq!(
1949 err.to_string(),
1950 "Invalid argument error: Offsets must be non-negative and within the length of the Array"
1951 );
1952
1953 let offsets = Some(vec![0, 1].into());
1954 let err =
1955 UnionArray::try_new(fields.clone(), type_ids.clone(), offsets, children).unwrap_err();
1956
1957 assert_eq!(
1958 err.to_string(),
1959 "Invalid argument error: Type Ids and Offsets lengths must match"
1960 );
1961
1962 let err = UnionArray::try_new(fields.clone(), type_ids, None, vec![]).unwrap_err();
1963
1964 assert_eq!(
1965 err.to_string(),
1966 "Invalid argument error: Union fields length must match child arrays length"
1967 );
1968 }
1969
1970 #[test]
1971 fn test_logical_nulls_fast_paths() {
1972 let array = UnionArray::try_new(UnionFields::empty(), vec![].into(), None, vec![]).unwrap();
1974
1975 assert_eq!(array.logical_nulls(), None);
1976
1977 let fields = UnionFields::try_new(
1978 [1, 3],
1979 [
1980 Field::new("a", DataType::Int8, false), Field::new("b", DataType::Int8, false), ],
1983 )
1984 .unwrap();
1985 let array = UnionArray::try_new(
1986 fields,
1987 vec![1].into(),
1988 None,
1989 vec![
1990 Arc::new(Int8Array::from_value(5, 1)),
1991 Arc::new(Int8Array::from_value(5, 1)),
1992 ],
1993 )
1994 .unwrap();
1995
1996 assert_eq!(array.logical_nulls(), None);
1997
1998 let nullable_fields = UnionFields::try_new(
1999 [1, 3],
2000 [
2001 Field::new("a", DataType::Int8, true), Field::new("b", DataType::Int8, true), ],
2004 )
2005 .unwrap();
2006 let array = UnionArray::try_new(
2007 nullable_fields.clone(),
2008 vec![1, 1].into(),
2009 None,
2010 vec![
2011 Arc::new(Int8Array::from_value(-5, 2)), Arc::new(Int8Array::from_value(-5, 2)), ],
2014 )
2015 .unwrap();
2016
2017 assert_eq!(array.logical_nulls(), None);
2018
2019 let array = UnionArray::try_new(
2020 nullable_fields.clone(),
2021 vec![1, 1].into(),
2022 None,
2023 vec![
2024 Arc::new(Int8Array::new_null(2)), Arc::new(Int8Array::new_null(2)), ],
2028 )
2029 .unwrap();
2030
2031 assert_eq!(array.logical_nulls(), Some(NullBuffer::new_null(2)));
2032
2033 let array = UnionArray::try_new(
2034 nullable_fields.clone(),
2035 vec![1, 1].into(),
2036 Some(vec![0, 1].into()),
2037 vec![
2038 Arc::new(Int8Array::new_null(3)), Arc::new(Int8Array::new_null(3)), ],
2042 )
2043 .unwrap();
2044
2045 assert_eq!(array.logical_nulls(), Some(NullBuffer::new_null(2)));
2046 }
2047
2048 #[test]
2049 fn test_dense_union_logical_nulls_gather() {
2050 let int_array = Int32Array::from(vec![1, 2]);
2052 let float_array = Float64Array::from(vec![Some(3.2), None]);
2053 let str_array = StringArray::new_null(1);
2054 let type_ids = [1, 1, 3, 3, 4, 4].into_iter().collect::<ScalarBuffer<i8>>();
2055 let offsets = [0, 1, 0, 1, 0, 0]
2056 .into_iter()
2057 .collect::<ScalarBuffer<i32>>();
2058
2059 let children = vec![
2060 Arc::new(int_array) as Arc<dyn Array>,
2061 Arc::new(float_array),
2062 Arc::new(str_array),
2063 ];
2064
2065 let array = UnionArray::try_new(union_fields(), type_ids, Some(offsets), children).unwrap();
2066
2067 let expected = BooleanBuffer::from(vec![true, true, true, false, false, false]);
2068
2069 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2070 assert_eq!(expected, array.gather_nulls(array.fields_logical_nulls()));
2071 }
2072
2073 #[test]
2074 fn test_dense_union_one_field_nonzero_type_id_logical_nulls() {
2075 let fields = UnionFields::try_new([5], [Field::new("a", DataType::Int32, true)]).unwrap();
2076 let child = Arc::new(Int32Array::from(vec![None, Some(1)]));
2077 let array = UnionArray::try_new(
2078 fields,
2079 vec![5, 5, 5].into(),
2080 Some(vec![1, 0, 1].into()),
2081 vec![child],
2082 )
2083 .unwrap();
2084
2085 let expected = NullBuffer::from(vec![true, false, true]);
2086 assert_eq!(array.logical_nulls(), Some(expected));
2087 assert_eq!(array.logical_null_count(), 1);
2088 }
2089
2090 #[test]
2091 fn test_sparse_union_logical_nulls_mask_all_nulls_skip_one() {
2092 let fields: UnionFields = [
2093 (1, Arc::new(Field::new("A", DataType::Int32, true))),
2094 (3, Arc::new(Field::new("B", DataType::Float64, true))),
2095 ]
2096 .into_iter()
2097 .collect();
2098
2099 let int_array = Int32Array::new_null(4);
2101 let float_array = Float64Array::from(vec![None, None, Some(3.2), None]);
2102 let type_ids = [1, 1, 3, 3].into_iter().collect::<ScalarBuffer<i8>>();
2103
2104 let children = vec![Arc::new(int_array) as Arc<dyn Array>, Arc::new(float_array)];
2105
2106 let array = UnionArray::try_new(fields.clone(), type_ids, None, children).unwrap();
2107
2108 let expected = BooleanBuffer::from(vec![false, false, true, false]);
2109
2110 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2111 assert_eq!(
2112 expected,
2113 array.mask_sparse_all_with_nulls_skip_one(array.fields_logical_nulls())
2114 );
2115
2116 let len = 2 * 64 + 32;
2118
2119 let int_array = Int32Array::new_null(len);
2120 let float_array = Float64Array::from_iter([Some(3.2), None].into_iter().cycle().take(len));
2121 let type_ids = ScalarBuffer::from_iter([1, 1, 3, 3].into_iter().cycle().take(len));
2122
2123 let array = UnionArray::try_new(
2124 fields,
2125 type_ids,
2126 None,
2127 vec![Arc::new(int_array), Arc::new(float_array)],
2128 )
2129 .unwrap();
2130
2131 let expected =
2132 BooleanBuffer::from_iter([false, false, true, false].into_iter().cycle().take(len));
2133
2134 assert_eq!(array.len(), len);
2135 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2136 assert_eq!(
2137 expected,
2138 array.mask_sparse_all_with_nulls_skip_one(array.fields_logical_nulls())
2139 );
2140 }
2141
2142 #[test]
2143 fn test_sparse_union_logical_mask_mixed_nulls_skip_fully_valid() {
2144 let int_array = Int32Array::from_value(2, 6);
2146 let float_array = Float64Array::from_value(4.2, 6);
2147 let str_array = StringArray::new_null(6);
2148 let type_ids = [1, 1, 3, 3, 4, 4].into_iter().collect::<ScalarBuffer<i8>>();
2149
2150 let children = vec![
2151 Arc::new(int_array) as Arc<dyn Array>,
2152 Arc::new(float_array),
2153 Arc::new(str_array),
2154 ];
2155
2156 let array = UnionArray::try_new(union_fields(), type_ids, None, children).unwrap();
2157
2158 let expected = BooleanBuffer::from(vec![true, true, true, true, false, false]);
2159
2160 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2161 assert_eq!(
2162 expected,
2163 array.mask_sparse_skip_without_nulls(array.fields_logical_nulls())
2164 );
2165
2166 let len = 2 * 64 + 32;
2168
2169 let int_array = Int32Array::from_value(2, len);
2170 let float_array = Float64Array::from_value(4.2, len);
2171 let str_array = StringArray::from_iter([None, Some("a")].into_iter().cycle().take(len));
2172 let type_ids = ScalarBuffer::from_iter([1, 1, 3, 3, 4, 4].into_iter().cycle().take(len));
2173
2174 let children = vec![
2175 Arc::new(int_array) as Arc<dyn Array>,
2176 Arc::new(float_array),
2177 Arc::new(str_array),
2178 ];
2179
2180 let array = UnionArray::try_new(union_fields(), type_ids, None, children).unwrap();
2181
2182 let expected = BooleanBuffer::from_iter(
2183 [true, true, true, true, false, true]
2184 .into_iter()
2185 .cycle()
2186 .take(len),
2187 );
2188
2189 assert_eq!(array.len(), len);
2190 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2191 assert_eq!(
2192 expected,
2193 array.mask_sparse_skip_without_nulls(array.fields_logical_nulls())
2194 );
2195 }
2196
2197 #[test]
2198 fn test_sparse_union_logical_mask_mixed_nulls_skip_fully_null() {
2199 let int_array = Int32Array::new_null(6);
2201 let float_array = Float64Array::from_value(4.2, 6);
2202 let str_array = StringArray::new_null(6);
2203 let type_ids = [1, 1, 3, 3, 4, 4].into_iter().collect::<ScalarBuffer<i8>>();
2204
2205 let children = vec![
2206 Arc::new(int_array) as Arc<dyn Array>,
2207 Arc::new(float_array),
2208 Arc::new(str_array),
2209 ];
2210
2211 let array = UnionArray::try_new(union_fields(), type_ids, None, children).unwrap();
2212
2213 let expected = BooleanBuffer::from(vec![false, false, true, true, false, false]);
2214
2215 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2216 assert_eq!(
2217 expected,
2218 array.mask_sparse_skip_fully_null(array.fields_logical_nulls())
2219 );
2220
2221 let len = 2 * 64 + 32;
2223
2224 let int_array = Int32Array::new_null(len);
2225 let float_array = Float64Array::from_value(4.2, len);
2226 let str_array = StringArray::new_null(len);
2227 let type_ids = ScalarBuffer::from_iter([1, 1, 3, 3, 4, 4].into_iter().cycle().take(len));
2228
2229 let children = vec![
2230 Arc::new(int_array) as Arc<dyn Array>,
2231 Arc::new(float_array),
2232 Arc::new(str_array),
2233 ];
2234
2235 let array = UnionArray::try_new(union_fields(), type_ids, None, children).unwrap();
2236
2237 let expected = BooleanBuffer::from_iter(
2238 [false, false, true, true, false, false]
2239 .into_iter()
2240 .cycle()
2241 .take(len),
2242 );
2243
2244 assert_eq!(array.len(), len);
2245 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2246 assert_eq!(
2247 expected,
2248 array.mask_sparse_skip_fully_null(array.fields_logical_nulls())
2249 );
2250 }
2251
2252 #[test]
2253 fn test_sparse_union_logical_nulls_gather() {
2254 let n_fields = 50;
2255
2256 let non_null = Int32Array::from_value(2, 4);
2257 let mixed = Int32Array::from(vec![None, None, Some(1), None]);
2258 let fully_null = Int32Array::new_null(4);
2259
2260 let array = UnionArray::try_new(
2261 (1..)
2262 .step_by(2)
2263 .map(|i| {
2264 (
2265 i,
2266 Arc::new(Field::new(format!("f{i}"), DataType::Int32, true)),
2267 )
2268 })
2269 .take(n_fields)
2270 .collect(),
2271 vec![1, 3, 3, 5].into(),
2272 None,
2273 [
2274 Arc::new(non_null) as ArrayRef,
2275 Arc::new(mixed),
2276 Arc::new(fully_null),
2277 ]
2278 .into_iter()
2279 .cycle()
2280 .take(n_fields)
2281 .collect(),
2282 )
2283 .unwrap();
2284
2285 let expected = BooleanBuffer::from(vec![true, false, true, false]);
2286
2287 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2288 assert_eq!(expected, array.gather_nulls(array.fields_logical_nulls()));
2289 }
2290
2291 fn union_fields() -> UnionFields {
2292 [
2293 (1, Arc::new(Field::new("A", DataType::Int32, true))),
2294 (3, Arc::new(Field::new("B", DataType::Float64, true))),
2295 (4, Arc::new(Field::new("C", DataType::Utf8, true))),
2296 ]
2297 .into_iter()
2298 .collect()
2299 }
2300
2301 #[test]
2302 fn test_is_nullable() {
2303 assert!(!create_union_array(false, false).is_nullable());
2304 assert!(create_union_array(true, false).is_nullable());
2305 assert!(create_union_array(false, true).is_nullable());
2306 assert!(create_union_array(true, true).is_nullable());
2307 }
2308
2309 fn create_union_array(int_nullable: bool, float_nullable: bool) -> UnionArray {
2316 let int_array = if int_nullable {
2317 Int32Array::from(vec![Some(1), None, Some(3)])
2318 } else {
2319 Int32Array::from(vec![1, 2, 3])
2320 };
2321 let float_array = if float_nullable {
2322 Float64Array::from(vec![Some(3.2), None, Some(4.2)])
2323 } else {
2324 Float64Array::from(vec![3.2, 4.2, 5.2])
2325 };
2326 let type_ids = [0, 1, 0].into_iter().collect::<ScalarBuffer<i8>>();
2327 let offsets = [0, 0, 0].into_iter().collect::<ScalarBuffer<i32>>();
2328 let union_fields = [
2329 (0, Arc::new(Field::new("A", DataType::Int32, true))),
2330 (1, Arc::new(Field::new("B", DataType::Float64, true))),
2331 ]
2332 .into_iter()
2333 .collect::<UnionFields>();
2334
2335 let children = vec![Arc::new(int_array) as Arc<dyn Array>, Arc::new(float_array)];
2336
2337 UnionArray::try_new(union_fields, type_ids, Some(offsets), children).unwrap()
2338 }
2339}