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, Buffer, 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 (data_type, len, _nulls, offset, buffers, child_data) = data.into_parts();
684
685 let (fields, mode) = match &data_type {
686 DataType::Union(fields, mode) => (fields, mode),
687 d => panic!("UnionArray expected ArrayData with type Union got {d}"),
688 };
689
690 let (type_ids, offsets) = match mode {
691 UnionMode::Sparse => {
692 let [buffer]: [Buffer; 1] = buffers.try_into().expect("1 buffer for type_ids");
693 (ScalarBuffer::new(buffer, offset, len), None)
694 }
695 UnionMode::Dense => {
696 let [type_ids_buffer, offsets_buffer]: [Buffer; 2] = buffers
697 .try_into()
698 .expect("2 buffers for type_ids and offsets");
699 (
700 ScalarBuffer::new(type_ids_buffer, offset, len),
701 Some(ScalarBuffer::new(offsets_buffer, offset, len)),
702 )
703 }
704 };
705
706 let max_id = fields.iter().map(|(i, _)| i).max().unwrap_or_default() as usize;
707 let mut boxed_fields = vec![None; max_id + 1];
708 for (cd, (field_id, _)) in child_data.into_iter().zip(fields.iter()) {
709 let cd = match mode {
710 UnionMode::Sparse => cd.slice(offset, len),
711 UnionMode::Dense => cd,
712 };
713 boxed_fields[field_id as usize] = Some(make_array(cd));
714 }
715 Self {
716 data_type,
717 type_ids,
718 offsets,
719 fields: boxed_fields,
720 }
721 }
722}
723
724impl From<UnionArray> for ArrayData {
725 fn from(array: UnionArray) -> Self {
726 let len = array.len();
727 let f = match &array.data_type {
728 DataType::Union(f, _) => f,
729 _ => unreachable!(),
730 };
731 let buffers = match array.offsets {
732 Some(o) => vec![array.type_ids.into_inner(), o.into_inner()],
733 None => vec![array.type_ids.into_inner()],
734 };
735
736 let child = f
737 .iter()
738 .map(|(i, _)| array.fields[i as usize].as_ref().unwrap().to_data())
739 .collect();
740
741 let builder = ArrayDataBuilder::new(array.data_type)
742 .len(len)
743 .buffers(buffers)
744 .child_data(child);
745 unsafe { builder.build_unchecked() }
746 }
747}
748
749unsafe impl Array for UnionArray {
751 fn as_any(&self) -> &dyn Any {
752 self
753 }
754
755 fn to_data(&self) -> ArrayData {
756 self.clone().into()
757 }
758
759 fn into_data(self) -> ArrayData {
760 self.into()
761 }
762
763 fn data_type(&self) -> &DataType {
764 &self.data_type
765 }
766
767 fn slice(&self, offset: usize, length: usize) -> ArrayRef {
768 Arc::new(self.slice(offset, length))
769 }
770
771 fn len(&self) -> usize {
772 self.type_ids.len()
773 }
774
775 fn is_empty(&self) -> bool {
776 self.type_ids.is_empty()
777 }
778
779 fn shrink_to_fit(&mut self) {
780 self.type_ids.shrink_to_fit();
781 if let Some(offsets) = &mut self.offsets {
782 offsets.shrink_to_fit();
783 }
784 for array in self.fields.iter_mut().flatten() {
785 array.shrink_to_fit();
786 }
787 self.fields.shrink_to_fit();
788 }
789
790 fn offset(&self) -> usize {
791 0
792 }
793
794 fn nulls(&self) -> Option<&NullBuffer> {
795 None
796 }
797
798 fn logical_nulls(&self) -> Option<NullBuffer> {
799 let fields = match self.data_type() {
800 DataType::Union(fields, _) => fields,
801 _ => unreachable!(),
802 };
803
804 if fields.len() <= 1 {
805 return self
806 .fields
807 .iter()
808 .enumerate()
809 .find_map(|(type_id, field_opt)| {
810 field_opt
811 .as_ref()
812 .and_then(|field| field.logical_nulls())
813 .map(|logical_nulls| {
814 if self.is_dense() {
815 self.gather_nulls(vec![(type_id as i8, logical_nulls)])
816 .into()
817 } else {
818 logical_nulls
819 }
820 })
821 });
822 }
823
824 let logical_nulls = self.fields_logical_nulls();
825
826 if logical_nulls.is_empty() {
827 return None;
828 }
829
830 let fully_null_count = logical_nulls
831 .iter()
832 .filter(|(_, nulls)| nulls.null_count() == nulls.len())
833 .count();
834
835 if fully_null_count == fields.len() {
836 if let Some((_, exactly_sized)) = logical_nulls
837 .iter()
838 .find(|(_, nulls)| nulls.len() == self.len())
839 {
840 return Some(exactly_sized.clone());
841 }
842
843 if let Some((_, bigger)) = logical_nulls
844 .iter()
845 .find(|(_, nulls)| nulls.len() > self.len())
846 {
847 return Some(bigger.slice(0, self.len()));
848 }
849
850 return Some(NullBuffer::new_null(self.len()));
851 }
852
853 let boolean_buffer = match &self.offsets {
854 Some(_) => self.gather_nulls(logical_nulls),
855 None => {
856 let gather_relative_cost = if cfg!(target_feature = "avx2") {
864 10
865 } else if cfg!(target_feature = "sse4.1") {
866 3
867 } else if cfg!(target_arch = "x86") || cfg!(target_arch = "x86_64") {
868 2
870 } else {
871 0
875 };
876
877 let strategies = [
878 (SparseStrategy::Gather, gather_relative_cost, true),
879 (
880 SparseStrategy::MaskAllFieldsWithNullsSkipOne,
881 fields.len() - 1,
882 fields.len() == logical_nulls.len(),
883 ),
884 (
885 SparseStrategy::MaskSkipWithoutNulls,
886 logical_nulls.len(),
887 true,
888 ),
889 (
890 SparseStrategy::MaskSkipFullyNull,
891 fields.len() - fully_null_count,
892 true,
893 ),
894 ];
895
896 let (strategy, _, _) = strategies
897 .iter()
898 .filter(|(_, _, applicable)| *applicable)
899 .min_by_key(|(_, cost, _)| cost)
900 .unwrap();
901
902 match strategy {
903 SparseStrategy::Gather => self.gather_nulls(logical_nulls),
904 SparseStrategy::MaskAllFieldsWithNullsSkipOne => {
905 self.mask_sparse_all_with_nulls_skip_one(logical_nulls)
906 }
907 SparseStrategy::MaskSkipWithoutNulls => {
908 self.mask_sparse_skip_without_nulls(logical_nulls)
909 }
910 SparseStrategy::MaskSkipFullyNull => {
911 self.mask_sparse_skip_fully_null(logical_nulls)
912 }
913 }
914 }
915 };
916
917 let null_buffer = NullBuffer::from(boolean_buffer);
918
919 if null_buffer.null_count() > 0 {
920 Some(null_buffer)
921 } else {
922 None
923 }
924 }
925
926 fn is_nullable(&self) -> bool {
927 self.fields
928 .iter()
929 .flatten()
930 .any(|field| field.is_nullable())
931 }
932
933 fn get_buffer_memory_size(&self) -> usize {
934 let mut sum = self.type_ids.inner().capacity();
935 if let Some(o) = self.offsets.as_ref() {
936 sum += o.inner().capacity()
937 }
938 self.fields
939 .iter()
940 .flat_map(|x| x.as_ref().map(|x| x.get_buffer_memory_size()))
941 .sum::<usize>()
942 + sum
943 }
944
945 fn get_array_memory_size(&self) -> usize {
946 let mut sum = self.type_ids.inner().capacity();
947 if let Some(o) = self.offsets.as_ref() {
948 sum += o.inner().capacity()
949 }
950 std::mem::size_of::<Self>()
951 + self
952 .fields
953 .iter()
954 .flat_map(|x| x.as_ref().map(|x| x.get_array_memory_size()))
955 .sum::<usize>()
956 + sum
957 }
958
959 #[cfg(feature = "pool")]
960 fn claim(&self, pool: &dyn arrow_buffer::MemoryPool) {
961 self.type_ids.claim(pool);
962 if let Some(offsets) = &self.offsets {
963 offsets.claim(pool);
964 }
965 for field in self.fields.iter().flatten() {
966 field.claim(pool);
967 }
968 }
969}
970
971impl std::fmt::Debug for UnionArray {
972 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
973 let header = if self.is_dense() {
974 "UnionArray(Dense)\n["
975 } else {
976 "UnionArray(Sparse)\n["
977 };
978 writeln!(f, "{header}")?;
979
980 writeln!(f, "-- type id buffer:")?;
981 writeln!(f, "{:?}", self.type_ids)?;
982
983 if let Some(offsets) = &self.offsets {
984 writeln!(f, "-- offsets buffer:")?;
985 writeln!(f, "{offsets:?}")?;
986 }
987
988 let fields = match self.data_type() {
989 DataType::Union(fields, _) => fields,
990 _ => unreachable!(),
991 };
992
993 for (type_id, field) in fields.iter() {
994 let child = self.child(type_id);
995 writeln!(
996 f,
997 "-- child {}: \"{}\" ({:?})",
998 type_id,
999 field.name(),
1000 field.data_type()
1001 )?;
1002 std::fmt::Debug::fmt(child, f)?;
1003 writeln!(f)?;
1004 }
1005 writeln!(f, "]")
1006 }
1007}
1008
1009enum SparseStrategy {
1014 Gather,
1016 MaskAllFieldsWithNullsSkipOne,
1018 MaskSkipWithoutNulls,
1020 MaskSkipFullyNull,
1022}
1023
1024#[derive(Copy, Clone)]
1025#[repr(usize)]
1026enum Mask {
1027 Zero = 0,
1028 #[allow(clippy::enum_clike_unportable_variant)]
1030 Max = usize::MAX,
1031}
1032
1033fn selection_mask(type_ids_chunk: &[i8], type_id: i8) -> u64 {
1034 type_ids_chunk
1035 .iter()
1036 .copied()
1037 .enumerate()
1038 .fold(0, |packed, (bit_idx, v)| {
1039 packed | (((v == type_id) as u64) << bit_idx)
1040 })
1041}
1042
1043fn without_nulls_selected(type_ids_chunk: &[i8], without_nulls_ids: &[i8]) -> u64 {
1045 without_nulls_ids
1046 .iter()
1047 .fold(0, |fully_valid_selected, field_type_id| {
1048 fully_valid_selected | selection_mask(type_ids_chunk, *field_type_id)
1049 })
1050}
1051
1052#[cfg(test)]
1053mod tests {
1054 use super::*;
1055 use std::collections::HashSet;
1056
1057 use crate::array::Int8Type;
1058 use crate::builder::UnionBuilder;
1059 use crate::cast::AsArray;
1060 use crate::types::{Float32Type, Float64Type, Int32Type, Int64Type};
1061 use crate::{Float64Array, Int32Array, Int64Array, StringArray};
1062 use crate::{Int8Array, RecordBatch};
1063 use arrow_buffer::Buffer;
1064 use arrow_schema::{Field, Schema};
1065
1066 #[test]
1067 fn test_dense_i32() {
1068 let mut builder = UnionBuilder::new_dense();
1069 builder.append::<Int32Type>("a", 1).unwrap();
1070 builder.append::<Int32Type>("b", 2).unwrap();
1071 builder.append::<Int32Type>("c", 3).unwrap();
1072 builder.append::<Int32Type>("a", 4).unwrap();
1073 builder.append::<Int32Type>("c", 5).unwrap();
1074 builder.append::<Int32Type>("a", 6).unwrap();
1075 builder.append::<Int32Type>("b", 7).unwrap();
1076 let union = builder.build().unwrap();
1077
1078 let expected_type_ids = vec![0_i8, 1, 2, 0, 2, 0, 1];
1079 let expected_offsets = vec![0_i32, 0, 0, 1, 1, 2, 1];
1080 let expected_array_values = [1_i32, 2, 3, 4, 5, 6, 7];
1081
1082 assert_eq!(*union.type_ids(), expected_type_ids);
1084 for (i, id) in expected_type_ids.iter().enumerate() {
1085 assert_eq!(id, &union.type_id(i));
1086 }
1087
1088 assert_eq!(*union.offsets().unwrap(), expected_offsets);
1090 for (i, id) in expected_offsets.iter().enumerate() {
1091 assert_eq!(union.value_offset(i), *id as usize);
1092 }
1093
1094 assert_eq!(
1096 *union.child(0).as_primitive::<Int32Type>().values(),
1097 [1_i32, 4, 6]
1098 );
1099 assert_eq!(
1100 *union.child(1).as_primitive::<Int32Type>().values(),
1101 [2_i32, 7]
1102 );
1103 assert_eq!(
1104 *union.child(2).as_primitive::<Int32Type>().values(),
1105 [3_i32, 5]
1106 );
1107
1108 assert_eq!(expected_array_values.len(), union.len());
1109 for (i, expected_value) in expected_array_values.iter().enumerate() {
1110 assert!(!union.is_null(i));
1111 let slot = union.value(i);
1112 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1113 assert_eq!(slot.len(), 1);
1114 let value = slot.value(0);
1115 assert_eq!(expected_value, &value);
1116 }
1117 }
1118
1119 #[test]
1120 fn slice_union_array_single_field() {
1121 let union_array = {
1124 let mut builder = UnionBuilder::new_dense();
1125 builder.append::<Int32Type>("a", 1).unwrap();
1126 builder.append_null::<Int32Type>("a").unwrap();
1127 builder.append::<Int32Type>("a", 3).unwrap();
1128 builder.append_null::<Int32Type>("a").unwrap();
1129 builder.append::<Int32Type>("a", 4).unwrap();
1130 builder.build().unwrap()
1131 };
1132
1133 let union_slice = union_array.slice(1, 3);
1135 let logical_nulls = union_slice.logical_nulls().unwrap();
1136
1137 assert_eq!(logical_nulls.len(), 3);
1138 assert!(logical_nulls.is_null(0));
1139 assert!(logical_nulls.is_valid(1));
1140 assert!(logical_nulls.is_null(2));
1141 }
1142
1143 #[test]
1144 #[cfg_attr(miri, ignore)]
1145 fn test_dense_i32_large() {
1146 let mut builder = UnionBuilder::new_dense();
1147
1148 let expected_type_ids = vec![0_i8; 1024];
1149 let expected_offsets: Vec<_> = (0..1024).collect();
1150 let expected_array_values: Vec<_> = (1..=1024).collect();
1151
1152 expected_array_values
1153 .iter()
1154 .for_each(|v| builder.append::<Int32Type>("a", *v).unwrap());
1155
1156 let union = builder.build().unwrap();
1157
1158 assert_eq!(*union.type_ids(), expected_type_ids);
1160 for (i, id) in expected_type_ids.iter().enumerate() {
1161 assert_eq!(id, &union.type_id(i));
1162 }
1163
1164 assert_eq!(*union.offsets().unwrap(), expected_offsets);
1166 for (i, id) in expected_offsets.iter().enumerate() {
1167 assert_eq!(union.value_offset(i), *id as usize);
1168 }
1169
1170 for (i, expected_value) in expected_array_values.iter().enumerate() {
1171 assert!(!union.is_null(i));
1172 let slot = union.value(i);
1173 let slot = slot.as_primitive::<Int32Type>();
1174 assert_eq!(slot.len(), 1);
1175 let value = slot.value(0);
1176 assert_eq!(expected_value, &value);
1177 }
1178 }
1179
1180 #[test]
1181 fn test_dense_mixed() {
1182 let mut builder = UnionBuilder::new_dense();
1183 builder.append::<Int32Type>("a", 1).unwrap();
1184 builder.append::<Int64Type>("c", 3).unwrap();
1185 builder.append::<Int32Type>("a", 4).unwrap();
1186 builder.append::<Int64Type>("c", 5).unwrap();
1187 builder.append::<Int32Type>("a", 6).unwrap();
1188 let union = builder.build().unwrap();
1189
1190 assert_eq!(5, union.len());
1191 for i in 0..union.len() {
1192 let slot = union.value(i);
1193 assert!(!union.is_null(i));
1194 match i {
1195 0 => {
1196 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1197 assert_eq!(slot.len(), 1);
1198 let value = slot.value(0);
1199 assert_eq!(1_i32, value);
1200 }
1201 1 => {
1202 let slot = slot.as_any().downcast_ref::<Int64Array>().unwrap();
1203 assert_eq!(slot.len(), 1);
1204 let value = slot.value(0);
1205 assert_eq!(3_i64, value);
1206 }
1207 2 => {
1208 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1209 assert_eq!(slot.len(), 1);
1210 let value = slot.value(0);
1211 assert_eq!(4_i32, value);
1212 }
1213 3 => {
1214 let slot = slot.as_any().downcast_ref::<Int64Array>().unwrap();
1215 assert_eq!(slot.len(), 1);
1216 let value = slot.value(0);
1217 assert_eq!(5_i64, value);
1218 }
1219 4 => {
1220 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1221 assert_eq!(slot.len(), 1);
1222 let value = slot.value(0);
1223 assert_eq!(6_i32, value);
1224 }
1225 _ => unreachable!(),
1226 }
1227 }
1228 }
1229
1230 #[test]
1231 fn test_dense_mixed_with_nulls() {
1232 let mut builder = UnionBuilder::new_dense();
1233 builder.append::<Int32Type>("a", 1).unwrap();
1234 builder.append::<Int64Type>("c", 3).unwrap();
1235 builder.append::<Int32Type>("a", 10).unwrap();
1236 builder.append_null::<Int32Type>("a").unwrap();
1237 builder.append::<Int32Type>("a", 6).unwrap();
1238 let union = builder.build().unwrap();
1239
1240 assert_eq!(5, union.len());
1241 for i in 0..union.len() {
1242 let slot = union.value(i);
1243 match i {
1244 0 => {
1245 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1246 assert!(!slot.is_null(0));
1247 assert_eq!(slot.len(), 1);
1248 let value = slot.value(0);
1249 assert_eq!(1_i32, value);
1250 }
1251 1 => {
1252 let slot = slot.as_any().downcast_ref::<Int64Array>().unwrap();
1253 assert!(!slot.is_null(0));
1254 assert_eq!(slot.len(), 1);
1255 let value = slot.value(0);
1256 assert_eq!(3_i64, value);
1257 }
1258 2 => {
1259 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1260 assert!(!slot.is_null(0));
1261 assert_eq!(slot.len(), 1);
1262 let value = slot.value(0);
1263 assert_eq!(10_i32, value);
1264 }
1265 3 => assert!(slot.is_null(0)),
1266 4 => {
1267 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1268 assert!(!slot.is_null(0));
1269 assert_eq!(slot.len(), 1);
1270 let value = slot.value(0);
1271 assert_eq!(6_i32, value);
1272 }
1273 _ => unreachable!(),
1274 }
1275 }
1276 }
1277
1278 #[test]
1279 fn test_dense_mixed_with_nulls_and_offset() {
1280 let mut builder = UnionBuilder::new_dense();
1281 builder.append::<Int32Type>("a", 1).unwrap();
1282 builder.append::<Int64Type>("c", 3).unwrap();
1283 builder.append::<Int32Type>("a", 10).unwrap();
1284 builder.append_null::<Int32Type>("a").unwrap();
1285 builder.append::<Int32Type>("a", 6).unwrap();
1286 let union = builder.build().unwrap();
1287
1288 let slice = union.slice(2, 3);
1289 let new_union = slice.as_any().downcast_ref::<UnionArray>().unwrap();
1290
1291 assert_eq!(3, new_union.len());
1292 for i in 0..new_union.len() {
1293 let slot = new_union.value(i);
1294 match i {
1295 0 => {
1296 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1297 assert!(!slot.is_null(0));
1298 assert_eq!(slot.len(), 1);
1299 let value = slot.value(0);
1300 assert_eq!(10_i32, value);
1301 }
1302 1 => assert!(slot.is_null(0)),
1303 2 => {
1304 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1305 assert!(!slot.is_null(0));
1306 assert_eq!(slot.len(), 1);
1307 let value = slot.value(0);
1308 assert_eq!(6_i32, value);
1309 }
1310 _ => unreachable!(),
1311 }
1312 }
1313 }
1314
1315 #[test]
1316 fn test_dense_mixed_with_str() {
1317 let string_array = StringArray::from(vec!["foo", "bar", "baz"]);
1318 let int_array = Int32Array::from(vec![5, 6]);
1319 let float_array = Float64Array::from(vec![10.0]);
1320
1321 let type_ids = [1, 0, 0, 2, 0, 1].into_iter().collect::<ScalarBuffer<i8>>();
1322 let offsets = [0, 0, 1, 0, 2, 1]
1323 .into_iter()
1324 .collect::<ScalarBuffer<i32>>();
1325
1326 let fields = [
1327 (0, Arc::new(Field::new("A", DataType::Utf8, false))),
1328 (1, Arc::new(Field::new("B", DataType::Int32, false))),
1329 (2, Arc::new(Field::new("C", DataType::Float64, false))),
1330 ]
1331 .into_iter()
1332 .collect::<UnionFields>();
1333 let children = [
1334 Arc::new(string_array) as Arc<dyn Array>,
1335 Arc::new(int_array),
1336 Arc::new(float_array),
1337 ]
1338 .into_iter()
1339 .collect();
1340 let array =
1341 UnionArray::try_new(fields, type_ids.clone(), Some(offsets.clone()), children).unwrap();
1342
1343 assert_eq!(*array.type_ids(), type_ids);
1345 for (i, id) in type_ids.iter().enumerate() {
1346 assert_eq!(id, &array.type_id(i));
1347 }
1348
1349 assert_eq!(*array.offsets().unwrap(), offsets);
1351 for (i, id) in offsets.iter().enumerate() {
1352 assert_eq!(*id as usize, array.value_offset(i));
1353 }
1354
1355 assert_eq!(6, array.len());
1357
1358 let slot = array.value(0);
1359 let value = slot.as_any().downcast_ref::<Int32Array>().unwrap().value(0);
1360 assert_eq!(5, value);
1361
1362 let slot = array.value(1);
1363 let value = slot
1364 .as_any()
1365 .downcast_ref::<StringArray>()
1366 .unwrap()
1367 .value(0);
1368 assert_eq!("foo", value);
1369
1370 let slot = array.value(2);
1371 let value = slot
1372 .as_any()
1373 .downcast_ref::<StringArray>()
1374 .unwrap()
1375 .value(0);
1376 assert_eq!("bar", value);
1377
1378 let slot = array.value(3);
1379 let value = slot
1380 .as_any()
1381 .downcast_ref::<Float64Array>()
1382 .unwrap()
1383 .value(0);
1384 assert_eq!(10.0, value);
1385
1386 let slot = array.value(4);
1387 let value = slot
1388 .as_any()
1389 .downcast_ref::<StringArray>()
1390 .unwrap()
1391 .value(0);
1392 assert_eq!("baz", value);
1393
1394 let slot = array.value(5);
1395 let value = slot.as_any().downcast_ref::<Int32Array>().unwrap().value(0);
1396 assert_eq!(6, value);
1397 }
1398
1399 #[test]
1400 fn test_sparse_i32() {
1401 let mut builder = UnionBuilder::new_sparse();
1402 builder.append::<Int32Type>("a", 1).unwrap();
1403 builder.append::<Int32Type>("b", 2).unwrap();
1404 builder.append::<Int32Type>("c", 3).unwrap();
1405 builder.append::<Int32Type>("a", 4).unwrap();
1406 builder.append::<Int32Type>("c", 5).unwrap();
1407 builder.append::<Int32Type>("a", 6).unwrap();
1408 builder.append::<Int32Type>("b", 7).unwrap();
1409 let union = builder.build().unwrap();
1410
1411 let expected_type_ids = vec![0_i8, 1, 2, 0, 2, 0, 1];
1412 let expected_array_values = [1_i32, 2, 3, 4, 5, 6, 7];
1413
1414 assert_eq!(*union.type_ids(), expected_type_ids);
1416 for (i, id) in expected_type_ids.iter().enumerate() {
1417 assert_eq!(id, &union.type_id(i));
1418 }
1419
1420 assert!(union.offsets().is_none());
1422
1423 assert_eq!(
1425 *union.child(0).as_primitive::<Int32Type>().values(),
1426 [1_i32, 0, 0, 4, 0, 6, 0],
1427 );
1428 assert_eq!(
1429 *union.child(1).as_primitive::<Int32Type>().values(),
1430 [0_i32, 2_i32, 0, 0, 0, 0, 7]
1431 );
1432 assert_eq!(
1433 *union.child(2).as_primitive::<Int32Type>().values(),
1434 [0_i32, 0, 3_i32, 0, 5, 0, 0]
1435 );
1436
1437 assert_eq!(expected_array_values.len(), union.len());
1438 for (i, expected_value) in expected_array_values.iter().enumerate() {
1439 assert!(!union.is_null(i));
1440 let slot = union.value(i);
1441 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1442 assert_eq!(slot.len(), 1);
1443 let value = slot.value(0);
1444 assert_eq!(expected_value, &value);
1445 }
1446 }
1447
1448 #[test]
1449 fn test_sparse_mixed() {
1450 let mut builder = UnionBuilder::new_sparse();
1451 builder.append::<Int32Type>("a", 1).unwrap();
1452 builder.append::<Float64Type>("c", 3.0).unwrap();
1453 builder.append::<Int32Type>("a", 4).unwrap();
1454 builder.append::<Float64Type>("c", 5.0).unwrap();
1455 builder.append::<Int32Type>("a", 6).unwrap();
1456 let union = builder.build().unwrap();
1457
1458 let expected_type_ids = vec![0_i8, 1, 0, 1, 0];
1459
1460 assert_eq!(*union.type_ids(), expected_type_ids);
1462 for (i, id) in expected_type_ids.iter().enumerate() {
1463 assert_eq!(id, &union.type_id(i));
1464 }
1465
1466 assert!(union.offsets().is_none());
1468
1469 for i in 0..union.len() {
1470 let slot = union.value(i);
1471 assert!(!union.is_null(i));
1472 match i {
1473 0 => {
1474 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1475 assert_eq!(slot.len(), 1);
1476 let value = slot.value(0);
1477 assert_eq!(1_i32, value);
1478 }
1479 1 => {
1480 let slot = slot.as_any().downcast_ref::<Float64Array>().unwrap();
1481 assert_eq!(slot.len(), 1);
1482 let value = slot.value(0);
1483 assert_eq!(value, 3_f64);
1484 }
1485 2 => {
1486 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1487 assert_eq!(slot.len(), 1);
1488 let value = slot.value(0);
1489 assert_eq!(4_i32, value);
1490 }
1491 3 => {
1492 let slot = slot.as_any().downcast_ref::<Float64Array>().unwrap();
1493 assert_eq!(slot.len(), 1);
1494 let value = slot.value(0);
1495 assert_eq!(5_f64, value);
1496 }
1497 4 => {
1498 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1499 assert_eq!(slot.len(), 1);
1500 let value = slot.value(0);
1501 assert_eq!(6_i32, value);
1502 }
1503 _ => unreachable!(),
1504 }
1505 }
1506 }
1507
1508 #[test]
1509 fn test_sparse_mixed_with_nulls() {
1510 let mut builder = UnionBuilder::new_sparse();
1511 builder.append::<Int32Type>("a", 1).unwrap();
1512 builder.append_null::<Int32Type>("a").unwrap();
1513 builder.append::<Float64Type>("c", 3.0).unwrap();
1514 builder.append::<Int32Type>("a", 4).unwrap();
1515 let union = builder.build().unwrap();
1516
1517 let expected_type_ids = vec![0_i8, 0, 1, 0];
1518
1519 assert_eq!(*union.type_ids(), expected_type_ids);
1521 for (i, id) in expected_type_ids.iter().enumerate() {
1522 assert_eq!(id, &union.type_id(i));
1523 }
1524
1525 assert!(union.offsets().is_none());
1527
1528 for i in 0..union.len() {
1529 let slot = union.value(i);
1530 match i {
1531 0 => {
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!(1_i32, value);
1537 }
1538 1 => assert!(slot.is_null(0)),
1539 2 => {
1540 let slot = slot.as_any().downcast_ref::<Float64Array>().unwrap();
1541 assert!(!slot.is_null(0));
1542 assert_eq!(slot.len(), 1);
1543 let value = slot.value(0);
1544 assert_eq!(value, 3_f64);
1545 }
1546 3 => {
1547 let slot = slot.as_any().downcast_ref::<Int32Array>().unwrap();
1548 assert!(!slot.is_null(0));
1549 assert_eq!(slot.len(), 1);
1550 let value = slot.value(0);
1551 assert_eq!(4_i32, value);
1552 }
1553 _ => unreachable!(),
1554 }
1555 }
1556 }
1557
1558 #[test]
1559 fn test_sparse_mixed_with_nulls_and_offset() {
1560 let mut builder = UnionBuilder::new_sparse();
1561 builder.append::<Int32Type>("a", 1).unwrap();
1562 builder.append_null::<Int32Type>("a").unwrap();
1563 builder.append::<Float64Type>("c", 3.0).unwrap();
1564 builder.append_null::<Float64Type>("c").unwrap();
1565 builder.append::<Int32Type>("a", 4).unwrap();
1566 let union = builder.build().unwrap();
1567
1568 let slice = union.slice(1, 4);
1569 let new_union = slice.as_any().downcast_ref::<UnionArray>().unwrap();
1570
1571 assert_eq!(4, new_union.len());
1572 for i in 0..new_union.len() {
1573 let slot = new_union.value(i);
1574 match i {
1575 0 => assert!(slot.is_null(0)),
1576 1 => {
1577 let slot = slot.as_primitive::<Float64Type>();
1578 assert!(!slot.is_null(0));
1579 assert_eq!(slot.len(), 1);
1580 let value = slot.value(0);
1581 assert_eq!(value, 3_f64);
1582 }
1583 2 => assert!(slot.is_null(0)),
1584 3 => {
1585 let slot = slot.as_primitive::<Int32Type>();
1586 assert!(!slot.is_null(0));
1587 assert_eq!(slot.len(), 1);
1588 let value = slot.value(0);
1589 assert_eq!(4_i32, value);
1590 }
1591 _ => unreachable!(),
1592 }
1593 }
1594 }
1595
1596 fn test_union_validity(union_array: &UnionArray) {
1597 assert_eq!(union_array.null_count(), 0);
1598
1599 for i in 0..union_array.len() {
1600 assert!(!union_array.is_null(i));
1601 assert!(union_array.is_valid(i));
1602 }
1603 }
1604
1605 #[test]
1606 fn test_union_array_validity() {
1607 let mut builder = UnionBuilder::new_sparse();
1608 builder.append::<Int32Type>("a", 1).unwrap();
1609 builder.append_null::<Int32Type>("a").unwrap();
1610 builder.append::<Float64Type>("c", 3.0).unwrap();
1611 builder.append_null::<Float64Type>("c").unwrap();
1612 builder.append::<Int32Type>("a", 4).unwrap();
1613 let union = builder.build().unwrap();
1614
1615 test_union_validity(&union);
1616
1617 let mut builder = UnionBuilder::new_dense();
1618 builder.append::<Int32Type>("a", 1).unwrap();
1619 builder.append_null::<Int32Type>("a").unwrap();
1620 builder.append::<Float64Type>("c", 3.0).unwrap();
1621 builder.append_null::<Float64Type>("c").unwrap();
1622 builder.append::<Int32Type>("a", 4).unwrap();
1623 let union = builder.build().unwrap();
1624
1625 test_union_validity(&union);
1626 }
1627
1628 #[test]
1629 fn test_type_check() {
1630 let mut builder = UnionBuilder::new_sparse();
1631 builder.append::<Float32Type>("a", 1.0).unwrap();
1632 let err = builder.append::<Int32Type>("a", 1).unwrap_err().to_string();
1633 assert!(
1634 err.contains(
1635 "Attempt to write col \"a\" with type Int32 doesn't match existing type Float32"
1636 ),
1637 "{}",
1638 err
1639 );
1640 }
1641
1642 #[test]
1643 fn slice_union_array() {
1644 fn create_union(mut builder: UnionBuilder) -> UnionArray {
1646 builder.append::<Int32Type>("a", 1).unwrap();
1647 builder.append_null::<Int32Type>("a").unwrap();
1648 builder.append::<Float64Type>("c", 3.0).unwrap();
1649 builder.append_null::<Float64Type>("c").unwrap();
1650 builder.append::<Int32Type>("a", 4).unwrap();
1651 builder.build().unwrap()
1652 }
1653
1654 fn create_batch(union: UnionArray) -> RecordBatch {
1655 let schema = Schema::new(vec![Field::new(
1656 "struct_array",
1657 union.data_type().clone(),
1658 true,
1659 )]);
1660
1661 RecordBatch::try_new(Arc::new(schema), vec![Arc::new(union)]).unwrap()
1662 }
1663
1664 fn test_slice_union(record_batch_slice: RecordBatch) {
1665 let union_slice = record_batch_slice
1666 .column(0)
1667 .as_any()
1668 .downcast_ref::<UnionArray>()
1669 .unwrap();
1670
1671 assert_eq!(union_slice.type_id(0), 0);
1672 assert_eq!(union_slice.type_id(1), 1);
1673 assert_eq!(union_slice.type_id(2), 1);
1674
1675 let slot = union_slice.value(0);
1676 let array = slot.as_primitive::<Int32Type>();
1677 assert_eq!(array.len(), 1);
1678 assert!(array.is_null(0));
1679
1680 let slot = union_slice.value(1);
1681 let array = slot.as_primitive::<Float64Type>();
1682 assert_eq!(array.len(), 1);
1683 assert!(array.is_valid(0));
1684 assert_eq!(array.value(0), 3.0);
1685
1686 let slot = union_slice.value(2);
1687 let array = slot.as_primitive::<Float64Type>();
1688 assert_eq!(array.len(), 1);
1689 assert!(array.is_null(0));
1690 }
1691
1692 let builder = UnionBuilder::new_sparse();
1694 let record_batch = create_batch(create_union(builder));
1695 let record_batch_slice = record_batch.slice(1, 3);
1697 test_slice_union(record_batch_slice);
1698
1699 let builder = UnionBuilder::new_dense();
1701 let record_batch = create_batch(create_union(builder));
1702 let record_batch_slice = record_batch.slice(1, 3);
1704 test_slice_union(record_batch_slice);
1705 }
1706
1707 #[test]
1708 fn test_union_from_sliced_array_data() {
1709 for mode in [UnionMode::Sparse, UnionMode::Dense] {
1710 let fields = UnionFields::try_new(
1711 [3, 7],
1712 [
1713 Field::new("ints", DataType::Int32, false),
1714 Field::new("floats", DataType::Float64, false),
1715 ],
1716 )
1717 .unwrap();
1718 let offsets = (mode == UnionMode::Dense).then(|| vec![0, 1, 2, 3].into());
1719 let array = UnionArray::try_new(
1720 fields,
1721 vec![3, 7, 3, 7].into(),
1722 offsets,
1723 vec![
1724 Arc::new(Int32Array::from(vec![10, 20, 30, 40])),
1725 Arc::new(Float64Array::from(vec![1.0, 2.0, 3.0, 4.0])),
1726 ],
1727 )
1728 .unwrap();
1729 for (offset, len) in [(1, 2), (0, 2), (4, 0), (0, 4)] {
1730 let expected = array.slice(offset, len);
1731 let actual = make_array(array.to_data().slice(offset, len));
1732 let actual = actual.as_any().downcast_ref::<UnionArray>().unwrap();
1733 for i in 0..len {
1734 assert_eq!(actual.value(i).to_data(), expected.value(i).to_data());
1735 }
1736 assert_eq!(actual.to_data(), expected.to_data());
1737 }
1738 }
1739 }
1740
1741 #[test]
1742 fn test_sparse_union_from_sliced_array_data_logical_nulls() {
1743 let child = Int32Array::from(vec![Some(10), None, Some(30)]);
1744 let fields =
1745 UnionFields::try_new([0], [Field::new("ints", DataType::Int32, true)]).unwrap();
1746 let array =
1747 UnionArray::try_new(fields, vec![0, 0, 0].into(), None, vec![Arc::new(child)]).unwrap();
1748 for (offset, len) in [(0, 1), (1, 1), (2, 1), (3, 0)] {
1749 let expected = array.slice(offset, len);
1750 let actual = make_array(array.to_data().slice(offset, len));
1751 assert_eq!(actual.logical_nulls(), expected.logical_nulls());
1752 assert_eq!(actual.to_data(), expected.to_data());
1753 }
1754 }
1755
1756 #[test]
1757 fn test_custom_type_ids() {
1758 let data_type = DataType::Union(
1759 UnionFields::try_new(
1760 vec![8, 4, 9],
1761 vec![
1762 Field::new("strings", DataType::Utf8, false),
1763 Field::new("integers", DataType::Int32, false),
1764 Field::new("floats", DataType::Float64, false),
1765 ],
1766 )
1767 .unwrap(),
1768 UnionMode::Dense,
1769 );
1770
1771 let string_array = StringArray::from(vec!["foo", "bar", "baz"]);
1772 let int_array = Int32Array::from(vec![5, 6, 4]);
1773 let float_array = Float64Array::from(vec![10.0]);
1774
1775 let type_ids = Buffer::from_vec(vec![4_i8, 8, 4, 8, 9, 4, 8]);
1776 let value_offsets = Buffer::from_vec(vec![0_i32, 0, 1, 1, 0, 2, 2]);
1777
1778 let data = ArrayData::builder(data_type)
1779 .len(7)
1780 .buffers(vec![type_ids, value_offsets])
1781 .child_data(vec![
1782 string_array.into_data(),
1783 int_array.into_data(),
1784 float_array.into_data(),
1785 ])
1786 .build()
1787 .unwrap();
1788
1789 let array = UnionArray::from(data);
1790
1791 let v = array.value(0);
1792 assert_eq!(v.data_type(), &DataType::Int32);
1793 assert_eq!(v.len(), 1);
1794 assert_eq!(v.as_primitive::<Int32Type>().value(0), 5);
1795
1796 let v = array.value(1);
1797 assert_eq!(v.data_type(), &DataType::Utf8);
1798 assert_eq!(v.len(), 1);
1799 assert_eq!(v.as_string::<i32>().value(0), "foo");
1800
1801 let v = array.value(2);
1802 assert_eq!(v.data_type(), &DataType::Int32);
1803 assert_eq!(v.len(), 1);
1804 assert_eq!(v.as_primitive::<Int32Type>().value(0), 6);
1805
1806 let v = array.value(3);
1807 assert_eq!(v.data_type(), &DataType::Utf8);
1808 assert_eq!(v.len(), 1);
1809 assert_eq!(v.as_string::<i32>().value(0), "bar");
1810
1811 let v = array.value(4);
1812 assert_eq!(v.data_type(), &DataType::Float64);
1813 assert_eq!(v.len(), 1);
1814 assert_eq!(v.as_primitive::<Float64Type>().value(0), 10.0);
1815
1816 let v = array.value(5);
1817 assert_eq!(v.data_type(), &DataType::Int32);
1818 assert_eq!(v.len(), 1);
1819 assert_eq!(v.as_primitive::<Int32Type>().value(0), 4);
1820
1821 let v = array.value(6);
1822 assert_eq!(v.data_type(), &DataType::Utf8);
1823 assert_eq!(v.len(), 1);
1824 assert_eq!(v.as_string::<i32>().value(0), "baz");
1825 }
1826
1827 #[test]
1828 fn into_parts() {
1829 let mut builder = UnionBuilder::new_dense();
1830 builder.append::<Int32Type>("a", 1).unwrap();
1831 builder.append::<Int8Type>("b", 2).unwrap();
1832 builder.append::<Int32Type>("a", 3).unwrap();
1833 let dense_union = builder.build().unwrap();
1834
1835 let field = [
1836 &Arc::new(Field::new("a", DataType::Int32, false)),
1837 &Arc::new(Field::new("b", DataType::Int8, false)),
1838 ];
1839 let (union_fields, type_ids, offsets, children) = dense_union.into_parts();
1840 assert_eq!(
1841 union_fields
1842 .iter()
1843 .map(|(_, field)| field)
1844 .collect::<Vec<_>>(),
1845 field
1846 );
1847 assert_eq!(type_ids, [0, 1, 0]);
1848 assert!(offsets.is_some());
1849 assert_eq!(offsets.as_ref().unwrap(), &[0, 0, 1]);
1850
1851 let result = UnionArray::try_new(union_fields, type_ids, offsets, children);
1852 assert!(result.is_ok());
1853 assert_eq!(result.unwrap().len(), 3);
1854
1855 let mut builder = UnionBuilder::new_sparse();
1856 builder.append::<Int32Type>("a", 1).unwrap();
1857 builder.append::<Int8Type>("b", 2).unwrap();
1858 builder.append::<Int32Type>("a", 3).unwrap();
1859 let sparse_union = builder.build().unwrap();
1860
1861 let (union_fields, type_ids, offsets, children) = sparse_union.into_parts();
1862 assert_eq!(type_ids, [0, 1, 0]);
1863 assert!(offsets.is_none());
1864
1865 let result = UnionArray::try_new(union_fields, type_ids, offsets, children);
1866 assert!(result.is_ok());
1867 assert_eq!(result.unwrap().len(), 3);
1868 }
1869
1870 #[test]
1871 fn into_parts_custom_type_ids() {
1872 let set_field_type_ids: [i8; 3] = [8, 4, 9];
1873 let data_type = DataType::Union(
1874 UnionFields::try_new(
1875 set_field_type_ids,
1876 [
1877 Field::new("strings", DataType::Utf8, false),
1878 Field::new("integers", DataType::Int32, false),
1879 Field::new("floats", DataType::Float64, false),
1880 ],
1881 )
1882 .unwrap(),
1883 UnionMode::Dense,
1884 );
1885 let string_array = StringArray::from(vec!["foo", "bar", "baz"]);
1886 let int_array = Int32Array::from(vec![5, 6, 4]);
1887 let float_array = Float64Array::from(vec![10.0]);
1888 let type_ids = Buffer::from_vec(vec![4_i8, 8, 4, 8, 9, 4, 8]);
1889 let value_offsets = Buffer::from_vec(vec![0_i32, 0, 1, 1, 0, 2, 2]);
1890 let data = ArrayData::builder(data_type)
1891 .len(7)
1892 .buffers(vec![type_ids, value_offsets])
1893 .child_data(vec![
1894 string_array.into_data(),
1895 int_array.into_data(),
1896 float_array.into_data(),
1897 ])
1898 .build()
1899 .unwrap();
1900 let array = UnionArray::from(data);
1901
1902 let (union_fields, type_ids, offsets, children) = array.into_parts();
1903 assert_eq!(
1904 type_ids.iter().collect::<HashSet<_>>(),
1905 set_field_type_ids.iter().collect::<HashSet<_>>()
1906 );
1907 let result = UnionArray::try_new(union_fields, type_ids, offsets, children);
1908 assert!(result.is_ok());
1909 let array = result.unwrap();
1910 assert_eq!(array.len(), 7);
1911 }
1912
1913 #[test]
1914 fn test_invalid() {
1915 let fields = UnionFields::try_new(
1916 [3, 2],
1917 [
1918 Field::new("a", DataType::Utf8, false),
1919 Field::new("b", DataType::Utf8, false),
1920 ],
1921 )
1922 .unwrap();
1923 let children = vec![
1924 Arc::new(StringArray::from_iter_values(["a", "b"])) as _,
1925 Arc::new(StringArray::from_iter_values(["c", "d"])) as _,
1926 ];
1927
1928 let type_ids = vec![3, 3, 2].into();
1929 let err =
1930 UnionArray::try_new(fields.clone(), type_ids, None, children.clone()).unwrap_err();
1931 assert_eq!(
1932 err.to_string(),
1933 "Invalid argument error: Sparse union child arrays must be equal in length to the length of the union"
1934 );
1935
1936 let type_ids = vec![1, 2].into();
1937 let err =
1938 UnionArray::try_new(fields.clone(), type_ids, None, children.clone()).unwrap_err();
1939 assert_eq!(
1940 err.to_string(),
1941 "Invalid argument error: Type Ids values must match one of the field type ids"
1942 );
1943
1944 let type_ids = vec![7, 2].into();
1945 let err = UnionArray::try_new(fields.clone(), type_ids, None, children).unwrap_err();
1946 assert_eq!(
1947 err.to_string(),
1948 "Invalid argument error: Type Ids values must match one of the field type ids"
1949 );
1950
1951 let children = vec![
1952 Arc::new(StringArray::from_iter_values(["a", "b"])) as _,
1953 Arc::new(StringArray::from_iter_values(["c"])) as _,
1954 ];
1955 let type_ids = ScalarBuffer::from(vec![3_i8, 3, 2]);
1956 let offsets = Some(vec![0, 1, 0].into());
1957 UnionArray::try_new(fields.clone(), type_ids.clone(), offsets, children.clone()).unwrap();
1958
1959 let offsets = Some(vec![0, 1, 1].into());
1960 let err = UnionArray::try_new(fields.clone(), type_ids.clone(), offsets, children.clone())
1961 .unwrap_err();
1962
1963 assert_eq!(
1964 err.to_string(),
1965 "Invalid argument error: Offsets must be non-negative and within the length of the Array"
1966 );
1967
1968 let offsets = Some(vec![0, 1].into());
1969 let err =
1970 UnionArray::try_new(fields.clone(), type_ids.clone(), offsets, children).unwrap_err();
1971
1972 assert_eq!(
1973 err.to_string(),
1974 "Invalid argument error: Type Ids and Offsets lengths must match"
1975 );
1976
1977 let err = UnionArray::try_new(fields.clone(), type_ids, None, vec![]).unwrap_err();
1978
1979 assert_eq!(
1980 err.to_string(),
1981 "Invalid argument error: Union fields length must match child arrays length"
1982 );
1983 }
1984
1985 #[test]
1986 fn test_logical_nulls_fast_paths() {
1987 let array = UnionArray::try_new(UnionFields::empty(), vec![].into(), None, vec![]).unwrap();
1989
1990 assert_eq!(array.logical_nulls(), None);
1991
1992 let fields = UnionFields::try_new(
1993 [1, 3],
1994 [
1995 Field::new("a", DataType::Int8, false), Field::new("b", DataType::Int8, false), ],
1998 )
1999 .unwrap();
2000 let array = UnionArray::try_new(
2001 fields,
2002 vec![1].into(),
2003 None,
2004 vec![
2005 Arc::new(Int8Array::from_value(5, 1)),
2006 Arc::new(Int8Array::from_value(5, 1)),
2007 ],
2008 )
2009 .unwrap();
2010
2011 assert_eq!(array.logical_nulls(), None);
2012
2013 let nullable_fields = UnionFields::try_new(
2014 [1, 3],
2015 [
2016 Field::new("a", DataType::Int8, true), Field::new("b", DataType::Int8, true), ],
2019 )
2020 .unwrap();
2021 let array = UnionArray::try_new(
2022 nullable_fields.clone(),
2023 vec![1, 1].into(),
2024 None,
2025 vec![
2026 Arc::new(Int8Array::from_value(-5, 2)), Arc::new(Int8Array::from_value(-5, 2)), ],
2029 )
2030 .unwrap();
2031
2032 assert_eq!(array.logical_nulls(), None);
2033
2034 let array = UnionArray::try_new(
2035 nullable_fields.clone(),
2036 vec![1, 1].into(),
2037 None,
2038 vec![
2039 Arc::new(Int8Array::new_null(2)), Arc::new(Int8Array::new_null(2)), ],
2043 )
2044 .unwrap();
2045
2046 assert_eq!(array.logical_nulls(), Some(NullBuffer::new_null(2)));
2047
2048 let array = UnionArray::try_new(
2049 nullable_fields.clone(),
2050 vec![1, 1].into(),
2051 Some(vec![0, 1].into()),
2052 vec![
2053 Arc::new(Int8Array::new_null(3)), Arc::new(Int8Array::new_null(3)), ],
2057 )
2058 .unwrap();
2059
2060 assert_eq!(array.logical_nulls(), Some(NullBuffer::new_null(2)));
2061 }
2062
2063 #[test]
2064 fn test_dense_union_logical_nulls_gather() {
2065 let int_array = Int32Array::from(vec![1, 2]);
2067 let float_array = Float64Array::from(vec![Some(3.2), None]);
2068 let str_array = StringArray::new_null(1);
2069 let type_ids = [1, 1, 3, 3, 4, 4].into_iter().collect::<ScalarBuffer<i8>>();
2070 let offsets = [0, 1, 0, 1, 0, 0]
2071 .into_iter()
2072 .collect::<ScalarBuffer<i32>>();
2073
2074 let children = vec![
2075 Arc::new(int_array) as Arc<dyn Array>,
2076 Arc::new(float_array),
2077 Arc::new(str_array),
2078 ];
2079
2080 let array = UnionArray::try_new(union_fields(), type_ids, Some(offsets), children).unwrap();
2081
2082 let expected = BooleanBuffer::from(vec![true, true, true, false, false, false]);
2083
2084 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2085 assert_eq!(expected, array.gather_nulls(array.fields_logical_nulls()));
2086 }
2087
2088 #[test]
2089 fn test_dense_union_one_field_nonzero_type_id_logical_nulls() {
2090 let fields = UnionFields::try_new([5], [Field::new("a", DataType::Int32, true)]).unwrap();
2091 let child = Arc::new(Int32Array::from(vec![None, Some(1)]));
2092 let array = UnionArray::try_new(
2093 fields,
2094 vec![5, 5, 5].into(),
2095 Some(vec![1, 0, 1].into()),
2096 vec![child],
2097 )
2098 .unwrap();
2099
2100 let expected = NullBuffer::from(vec![true, false, true]);
2101 assert_eq!(array.logical_nulls(), Some(expected));
2102 assert_eq!(array.logical_null_count(), 1);
2103 }
2104
2105 #[test]
2106 fn test_sparse_union_logical_nulls_mask_all_nulls_skip_one() {
2107 let fields: UnionFields = [
2108 (1, Arc::new(Field::new("A", DataType::Int32, true))),
2109 (3, Arc::new(Field::new("B", DataType::Float64, true))),
2110 ]
2111 .into_iter()
2112 .collect();
2113
2114 let int_array = Int32Array::new_null(4);
2116 let float_array = Float64Array::from(vec![None, None, Some(3.2), None]);
2117 let type_ids = [1, 1, 3, 3].into_iter().collect::<ScalarBuffer<i8>>();
2118
2119 let children = vec![Arc::new(int_array) as Arc<dyn Array>, Arc::new(float_array)];
2120
2121 let array = UnionArray::try_new(fields.clone(), type_ids, None, children).unwrap();
2122
2123 let expected = BooleanBuffer::from(vec![false, false, true, false]);
2124
2125 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2126 assert_eq!(
2127 expected,
2128 array.mask_sparse_all_with_nulls_skip_one(array.fields_logical_nulls())
2129 );
2130
2131 let len = 2 * 64 + 32;
2133
2134 let int_array = Int32Array::new_null(len);
2135 let float_array = Float64Array::from_iter([Some(3.2), None].into_iter().cycle().take(len));
2136 let type_ids = ScalarBuffer::from_iter([1, 1, 3, 3].into_iter().cycle().take(len));
2137
2138 let array = UnionArray::try_new(
2139 fields,
2140 type_ids,
2141 None,
2142 vec![Arc::new(int_array), Arc::new(float_array)],
2143 )
2144 .unwrap();
2145
2146 let expected =
2147 BooleanBuffer::from_iter([false, false, true, false].into_iter().cycle().take(len));
2148
2149 assert_eq!(array.len(), len);
2150 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2151 assert_eq!(
2152 expected,
2153 array.mask_sparse_all_with_nulls_skip_one(array.fields_logical_nulls())
2154 );
2155 }
2156
2157 #[test]
2158 fn test_sparse_union_logical_mask_mixed_nulls_skip_fully_valid() {
2159 let int_array = Int32Array::from_value(2, 6);
2161 let float_array = Float64Array::from_value(4.2, 6);
2162 let str_array = StringArray::new_null(6);
2163 let type_ids = [1, 1, 3, 3, 4, 4].into_iter().collect::<ScalarBuffer<i8>>();
2164
2165 let children = vec![
2166 Arc::new(int_array) as Arc<dyn Array>,
2167 Arc::new(float_array),
2168 Arc::new(str_array),
2169 ];
2170
2171 let array = UnionArray::try_new(union_fields(), type_ids, None, children).unwrap();
2172
2173 let expected = BooleanBuffer::from(vec![true, true, true, true, false, false]);
2174
2175 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2176 assert_eq!(
2177 expected,
2178 array.mask_sparse_skip_without_nulls(array.fields_logical_nulls())
2179 );
2180
2181 let len = 2 * 64 + 32;
2183
2184 let int_array = Int32Array::from_value(2, len);
2185 let float_array = Float64Array::from_value(4.2, len);
2186 let str_array = StringArray::from_iter([None, Some("a")].into_iter().cycle().take(len));
2187 let type_ids = ScalarBuffer::from_iter([1, 1, 3, 3, 4, 4].into_iter().cycle().take(len));
2188
2189 let children = vec![
2190 Arc::new(int_array) as Arc<dyn Array>,
2191 Arc::new(float_array),
2192 Arc::new(str_array),
2193 ];
2194
2195 let array = UnionArray::try_new(union_fields(), type_ids, None, children).unwrap();
2196
2197 let expected = BooleanBuffer::from_iter(
2198 [true, true, true, true, false, true]
2199 .into_iter()
2200 .cycle()
2201 .take(len),
2202 );
2203
2204 assert_eq!(array.len(), len);
2205 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2206 assert_eq!(
2207 expected,
2208 array.mask_sparse_skip_without_nulls(array.fields_logical_nulls())
2209 );
2210 }
2211
2212 #[test]
2213 fn test_sparse_union_logical_mask_mixed_nulls_skip_fully_null() {
2214 let int_array = Int32Array::new_null(6);
2216 let float_array = Float64Array::from_value(4.2, 6);
2217 let str_array = StringArray::new_null(6);
2218 let type_ids = [1, 1, 3, 3, 4, 4].into_iter().collect::<ScalarBuffer<i8>>();
2219
2220 let children = vec![
2221 Arc::new(int_array) as Arc<dyn Array>,
2222 Arc::new(float_array),
2223 Arc::new(str_array),
2224 ];
2225
2226 let array = UnionArray::try_new(union_fields(), type_ids, None, children).unwrap();
2227
2228 let expected = BooleanBuffer::from(vec![false, false, true, true, false, false]);
2229
2230 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2231 assert_eq!(
2232 expected,
2233 array.mask_sparse_skip_fully_null(array.fields_logical_nulls())
2234 );
2235
2236 let len = 2 * 64 + 32;
2238
2239 let int_array = Int32Array::new_null(len);
2240 let float_array = Float64Array::from_value(4.2, len);
2241 let str_array = StringArray::new_null(len);
2242 let type_ids = ScalarBuffer::from_iter([1, 1, 3, 3, 4, 4].into_iter().cycle().take(len));
2243
2244 let children = vec![
2245 Arc::new(int_array) as Arc<dyn Array>,
2246 Arc::new(float_array),
2247 Arc::new(str_array),
2248 ];
2249
2250 let array = UnionArray::try_new(union_fields(), type_ids, None, children).unwrap();
2251
2252 let expected = BooleanBuffer::from_iter(
2253 [false, false, true, true, false, false]
2254 .into_iter()
2255 .cycle()
2256 .take(len),
2257 );
2258
2259 assert_eq!(array.len(), len);
2260 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2261 assert_eq!(
2262 expected,
2263 array.mask_sparse_skip_fully_null(array.fields_logical_nulls())
2264 );
2265 }
2266
2267 #[test]
2268 fn test_sparse_union_logical_nulls_gather() {
2269 let n_fields = 50;
2270
2271 let non_null = Int32Array::from_value(2, 4);
2272 let mixed = Int32Array::from(vec![None, None, Some(1), None]);
2273 let fully_null = Int32Array::new_null(4);
2274
2275 let array = UnionArray::try_new(
2276 (1..)
2277 .step_by(2)
2278 .map(|i| {
2279 (
2280 i,
2281 Arc::new(Field::new(format!("f{i}"), DataType::Int32, true)),
2282 )
2283 })
2284 .take(n_fields)
2285 .collect(),
2286 vec![1, 3, 3, 5].into(),
2287 None,
2288 [
2289 Arc::new(non_null) as ArrayRef,
2290 Arc::new(mixed),
2291 Arc::new(fully_null),
2292 ]
2293 .into_iter()
2294 .cycle()
2295 .take(n_fields)
2296 .collect(),
2297 )
2298 .unwrap();
2299
2300 let expected = BooleanBuffer::from(vec![true, false, true, false]);
2301
2302 assert_eq!(expected, array.logical_nulls().unwrap().into_inner());
2303 assert_eq!(expected, array.gather_nulls(array.fields_logical_nulls()));
2304 }
2305
2306 fn union_fields() -> UnionFields {
2307 [
2308 (1, Arc::new(Field::new("A", DataType::Int32, true))),
2309 (3, Arc::new(Field::new("B", DataType::Float64, true))),
2310 (4, Arc::new(Field::new("C", DataType::Utf8, true))),
2311 ]
2312 .into_iter()
2313 .collect()
2314 }
2315
2316 #[test]
2317 fn test_is_nullable() {
2318 assert!(!create_union_array(false, false).is_nullable());
2319 assert!(create_union_array(true, false).is_nullable());
2320 assert!(create_union_array(false, true).is_nullable());
2321 assert!(create_union_array(true, true).is_nullable());
2322 }
2323
2324 fn create_union_array(int_nullable: bool, float_nullable: bool) -> UnionArray {
2331 let int_array = if int_nullable {
2332 Int32Array::from(vec![Some(1), None, Some(3)])
2333 } else {
2334 Int32Array::from(vec![1, 2, 3])
2335 };
2336 let float_array = if float_nullable {
2337 Float64Array::from(vec![Some(3.2), None, Some(4.2)])
2338 } else {
2339 Float64Array::from(vec![3.2, 4.2, 5.2])
2340 };
2341 let type_ids = [0, 1, 0].into_iter().collect::<ScalarBuffer<i8>>();
2342 let offsets = [0, 0, 0].into_iter().collect::<ScalarBuffer<i32>>();
2343 let union_fields = [
2344 (0, Arc::new(Field::new("A", DataType::Int32, true))),
2345 (1, Arc::new(Field::new("B", DataType::Float64, true))),
2346 ]
2347 .into_iter()
2348 .collect::<UnionFields>();
2349
2350 let children = vec![Arc::new(int_array) as Arc<dyn Array>, Arc::new(float_array)];
2351
2352 UnionArray::try_new(union_fields, type_ids, Some(offsets), children).unwrap()
2353 }
2354}