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