1use std::sync::Arc;
14
15use vortex_error::VortexExpect;
16use vortex_error::VortexResult;
17use vortex_error::vortex_ensure;
18use vortex_error::vortex_panic;
19use vortex_mask::Mask;
20
21use crate::ArrayRef;
22use crate::Canonical;
23use crate::ExecutionCtx;
24use crate::array::ArrayView;
25use crate::array::IntoArray;
26use crate::arrays::List;
27use crate::arrays::ListView;
28use crate::arrays::ListViewArray;
29use crate::arrays::PrimitiveArray;
30use crate::arrays::list::ListArraySlotsExt;
31use crate::arrays::listview::ListViewArraySlotsExt;
32use crate::arrays::listview::ListViewRebuildMode;
33use crate::builders::ArrayBuilder;
34use crate::builders::DEFAULT_BUILDER_CAPACITY;
35use crate::builders::PrimitiveBuilder;
36use crate::builders::UninitRange;
37use crate::builders::builder_with_capacity;
38use crate::builders::lazy_null_builder::LazyBitBufferBuilder;
39use crate::builtins::ArrayBuiltins;
40use crate::dtype::DType;
41use crate::dtype::IntegerPType;
42use crate::dtype::Nullability;
43use crate::dtype::OffsetBuilderPType;
44use crate::match_each_integer_ptype;
45use crate::scalar::ListScalar;
46use crate::scalar::Scalar;
47
48pub struct ListViewBuilder<O: OffsetBuilderPType, S: OffsetBuilderPType> {
58 dtype: DType,
60
61 elements_builder: Box<dyn ArrayBuilder>,
63
64 offsets_builder: PrimitiveBuilder<O>,
66
67 sizes_builder: PrimitiveBuilder<S>,
69
70 nulls: LazyBitBufferBuilder,
72
73 zero_copy_to_list: bool,
80}
81
82impl<O: OffsetBuilderPType, S: OffsetBuilderPType> ListViewBuilder<O, S> {
83 pub fn new(element_dtype: Arc<DType>, nullability: Nullability) -> Self {
85 Self::with_capacity(
86 element_dtype,
87 nullability,
88 DEFAULT_BUILDER_CAPACITY * 2,
91 DEFAULT_BUILDER_CAPACITY,
92 )
93 }
94
95 pub fn with_capacity(
103 element_dtype: Arc<DType>,
104 nullability: Nullability,
105 elements_capacity: usize,
106 capacity: usize,
107 ) -> Self {
108 let elements_builder = builder_with_capacity(&element_dtype, elements_capacity);
109
110 let offsets_builder =
111 PrimitiveBuilder::<O>::with_capacity(Nullability::NonNullable, capacity);
112 let sizes_builder =
113 PrimitiveBuilder::<S>::with_capacity(Nullability::NonNullable, capacity);
114
115 let nulls = LazyBitBufferBuilder::new(capacity);
116
117 Self {
118 dtype: DType::List(element_dtype, nullability),
119 elements_builder,
120 offsets_builder,
121 sizes_builder,
122 nulls,
123 zero_copy_to_list: true,
124 }
125 }
126
127 pub fn append_array_as_list(
134 &mut self,
135 array: &ArrayRef,
136 ctx: &mut ExecutionCtx,
137 ) -> VortexResult<()> {
138 vortex_ensure!(
139 array.dtype() == self.element_dtype(),
140 "Array dtype {:?} does not match list element dtype {:?}",
141 array.dtype(),
142 self.element_dtype()
143 );
144
145 let curr_offset = self.elements_builder.len();
146 let num_elements = array.len();
147
148 assert!(
151 ((curr_offset + num_elements) as u64) < O::max_value_as_u64(),
152 "appending this list would cause an offset overflow"
153 );
154
155 self.elements_builder.reserve_exact(num_elements);
156 array.append_to_builder(self.elements_builder.as_mut(), ctx)?;
157 self.nulls.append_non_null();
158
159 self.offsets_builder.append_value(
160 O::from_usize(curr_offset).vortex_expect("Failed to convert from usize to `O`"),
161 );
162 self.sizes_builder.append_value(
163 S::from_usize(num_elements).vortex_expect("Failed to convert from usize to `S`"),
164 );
165
166 Ok(())
167 }
168
169 pub fn append_value(&mut self, value: ListScalar) -> VortexResult<()> {
174 let Some(elements) = value.elements() else {
175 vortex_ensure!(
177 self.dtype.is_nullable(),
178 "Cannot append null value to non-nullable list builder"
179 );
180 self.append_null();
181 return Ok(());
182 };
183
184 let curr_offset = self.elements_builder.len();
185 let num_elements = elements.len();
186
187 assert!(
190 ((curr_offset + num_elements) as u64) < O::max_value_as_u64(),
191 "appending this list would cause an offset overflow"
192 );
193
194 for scalar in elements {
195 self.elements_builder.append_scalar(&scalar)?;
196 }
197 self.nulls.append_non_null();
198
199 self.offsets_builder.append_value(
200 O::from_usize(curr_offset).vortex_expect("Failed to convert from usize to `O`"),
201 );
202 self.sizes_builder.append_value(
203 S::from_usize(num_elements).vortex_expect("Failed to convert from usize to `S`"),
204 );
205
206 Ok(())
207 }
208
209 pub fn finish_into_listview(&mut self) -> ListViewArray {
211 debug_assert_eq!(self.offsets_builder.len(), self.sizes_builder.len());
212 debug_assert_eq!(self.offsets_builder.len(), self.nulls.len());
213
214 let elements = self.elements_builder.finish();
215 let offsets = self.offsets_builder.finish();
216 let sizes = self.sizes_builder.finish();
217 let validity = self.nulls.finish_with_nullability(self.dtype.nullability());
218
219 let zero_copy_to_list = std::mem::replace(&mut self.zero_copy_to_list, true);
220
221 unsafe {
233 ListViewArray::new_unchecked(elements, offsets, sizes, validity)
234 .with_zero_copy_to_list(zero_copy_to_list)
235 }
236 }
237
238 pub fn element_dtype(&self) -> &DType {
241 let DType::List(element_dtype, ..) = &self.dtype else {
242 vortex_panic!("`ListViewBuilder` has an incorrect dtype: {}", self.dtype);
243 };
244
245 element_dtype
246 }
247
248 pub fn append_list_array(
255 &mut self,
256 array: ArrayView<'_, List>,
257 ctx: &mut ExecutionCtx,
258 ) -> VortexResult<()> {
259 if array.is_empty() {
260 return Ok(());
261 }
262
263 self.nulls
264 .append_validity_mask(&array.validity()?.execute_mask(array.len(), ctx)?);
265
266 let offsets = array.offsets().clone().execute::<PrimitiveArray>(ctx)?;
267 match_each_integer_ptype!(offsets.ptype(), |OffsetType| {
268 extend_from_list(
269 self,
270 array.elements(),
271 offsets.as_slice::<OffsetType>(),
272 ctx,
273 )?
274 });
275 Ok(())
276 }
277
278 pub fn append_listview_array(
289 &mut self,
290 array: ArrayView<'_, ListView>,
291 ctx: &mut ExecutionCtx,
292 ) -> VortexResult<()> {
293 if array.is_empty() {
294 return Ok(());
295 }
296
297 let listview = array
301 .into_owned()
302 .rebuild(ListViewRebuildMode::TrimElements, ctx)?;
303
304 self.zero_copy_to_list &= listview.is_zero_copy_to_list();
307
308 self.nulls
309 .append_validity_mask(&array.validity()?.execute_mask(array.len(), ctx)?);
310
311 let old_elements_len = self.elements_builder.len();
313 self.elements_builder
314 .reserve_exact(listview.elements().len());
315 listview
316 .elements()
317 .append_to_builder(self.elements_builder.as_mut(), ctx)?;
318 let new_elements_len = self.elements_builder.len();
319
320 let extend_length = listview.len();
322 self.sizes_builder.reserve_exact(extend_length);
323 self.offsets_builder.reserve_exact(extend_length);
324
325 let cast_sizes = listview
327 .sizes()
328 .clone()
329 .cast(self.sizes_builder.dtype().clone())?;
330 cast_sizes.append_to_builder(&mut self.sizes_builder, ctx)?;
331
332 let uninit_range = self.offsets_builder.uninit_range(extend_length);
335
336 let new_offsets = listview.offsets().clone().execute::<PrimitiveArray>(ctx)?;
338
339 match_each_integer_ptype!(new_offsets.ptype(), |A| {
340 adjust_and_extend_offsets::<O, A>(
341 uninit_range,
342 new_offsets,
343 old_elements_len,
344 new_elements_len,
345 );
346 });
347 Ok(())
348 }
349}
350
351impl<O: OffsetBuilderPType, S: OffsetBuilderPType> ArrayBuilder for ListViewBuilder<O, S> {
352 fn as_any(&self) -> &dyn std::any::Any {
353 self
354 }
355
356 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
357 self
358 }
359
360 fn dtype(&self) -> &DType {
361 &self.dtype
362 }
363
364 fn len(&self) -> usize {
365 self.offsets_builder.len()
366 }
367
368 fn append_zeros(&mut self, n: usize) {
369 debug_assert_eq!(self.offsets_builder.len(), self.sizes_builder.len());
370 debug_assert_eq!(self.offsets_builder.len(), self.nulls.len());
371
372 let curr_offset = self.elements_builder.len();
374
375 for _ in 0..n {
378 self.offsets_builder.append_value(
379 O::from_usize(curr_offset).vortex_expect("Failed to convert from usize to `O`"),
380 );
381 self.sizes_builder.append_value(S::zero());
382 }
383
384 self.nulls.append_n_non_nulls(n);
385 }
386
387 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
388 debug_assert_eq!(self.offsets_builder.len(), self.sizes_builder.len());
389 debug_assert_eq!(self.offsets_builder.len(), self.nulls.len());
390
391 let curr_offset = self.elements_builder.len();
393
394 for _ in 0..n {
396 self.offsets_builder.append_value(
397 O::from_usize(curr_offset).vortex_expect("Failed to convert from usize to `O`"),
398 );
399 self.sizes_builder.append_value(S::zero());
400 }
401
402 self.nulls.append_n_nulls(n);
404 }
405
406 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
407 vortex_ensure!(
408 scalar.dtype() == self.dtype(),
409 "ListViewBuilder expected scalar with dtype {}, got {}",
410 self.dtype(),
411 scalar.dtype()
412 );
413
414 let list_scalar = scalar.as_list();
415 self.append_value(list_scalar)
416 }
417
418 fn reserve_exact(&mut self, capacity: usize) {
419 self.elements_builder.reserve_exact(capacity * 2);
420 self.offsets_builder.reserve_exact(capacity);
421 self.sizes_builder.reserve_exact(capacity);
422 self.nulls.reserve_exact(capacity);
423 }
424
425 unsafe fn set_validity_unchecked(&mut self, validity: Mask) {
426 self.nulls = LazyBitBufferBuilder::from_validity_mask(validity);
427 }
428
429 fn finish(&mut self) -> ArrayRef {
430 self.finish_into_listview().into_array()
431 }
432
433 fn finish_into_canonical(&mut self, _ctx: &mut ExecutionCtx) -> Canonical {
434 Canonical::List(self.finish_into_listview())
435 }
436}
437
438fn extend_from_list<O, S, OffsetType>(
444 builder: &mut ListViewBuilder<O, S>,
445 elements: &ArrayRef,
446 offsets: &[OffsetType],
447 ctx: &mut ExecutionCtx,
448) -> VortexResult<()>
449where
450 O: OffsetBuilderPType,
451 S: OffsetBuilderPType,
452 OffsetType: IntegerPType,
453{
454 let num_lists = offsets.len() - 1;
455 let first: usize = offsets[0].as_();
456 let last: usize = offsets[num_lists].as_();
457
458 let elements_base = builder.elements_builder.len();
459
460 assert!(
463 ((elements_base + (last - first)) as u64) < O::max_value_as_u64(),
464 "appending this list would cause an offset overflow"
465 );
466
467 if last > first {
468 builder.elements_builder.reserve_exact(last - first);
469 elements
470 .slice(first..last)?
471 .append_to_builder(builder.elements_builder.as_mut(), ctx)?;
472 }
473
474 builder.offsets_builder.reserve_exact(num_lists);
475 builder.sizes_builder.reserve_exact(num_lists);
476 let mut offsets_range = builder.offsets_builder.uninit_range(num_lists);
477 let mut sizes_range = builder.sizes_builder.uninit_range(num_lists);
478 for i in 0..num_lists {
479 let start: usize = offsets[i].as_();
480 let end: usize = offsets[i + 1].as_();
481 offsets_range.set_value(
482 i,
483 O::from_usize(start - first + elements_base)
484 .vortex_expect("Failed to convert from usize to `O`"),
485 );
486 sizes_range.set_value(
487 i,
488 S::from_usize(end - start).vortex_expect("Failed to convert from usize to `S`"),
489 );
490 }
491 unsafe { offsets_range.finish() };
494 unsafe { sizes_range.finish() };
495 Ok(())
496}
497
498fn adjust_and_extend_offsets<O: IntegerPType, A: IntegerPType>(
501 mut uninit_range: UninitRange<O>,
502 new_offsets: PrimitiveArray,
503 old_elements_len: usize,
504 new_elements_len: usize,
505) {
506 let new_offsets_slice = new_offsets.as_slice::<A>();
507 let old_elements_len = O::from_usize(old_elements_len)
508 .vortex_expect("the old elements length did not fit into the offset type (impossible)");
509 let new_elements_len = O::from_usize(new_elements_len)
510 .vortex_expect("the current elements length did not fit into the offset type (impossible)");
511
512 for i in 0..uninit_range.len() {
513 let new_offset = O::from_usize(
514 new_offsets_slice[i]
515 .to_usize()
516 .vortex_expect("Offsets must always fit in usize"),
517 )
518 .vortex_expect("New offset somehow did not fit into the builder's offset type");
519
520 let adjusted_new_offset = new_offset + old_elements_len;
523 assert!(
524 adjusted_new_offset <= new_elements_len,
525 "[{i}/{}]: {new_offset} + {old_elements_len} \
526 = {adjusted_new_offset} <= {new_elements_len} failed",
527 uninit_range.len()
528 );
529
530 uninit_range.set_value(i, adjusted_new_offset);
531 }
532
533 unsafe { uninit_range.finish() };
536}
537
538#[cfg(test)]
539mod tests {
540 use std::sync::Arc;
541
542 use vortex_buffer::buffer;
543 use vortex_error::VortexExpect;
544 use vortex_error::VortexResult;
545
546 use super::ListViewBuilder;
547 use crate::IntoArray;
548 use crate::VortexSessionExecute;
549 use crate::array_session;
550 use crate::arrays::ConstantArray;
551 use crate::arrays::ListArray;
552 use crate::arrays::ListViewArray;
553 use crate::arrays::listview::ListViewArrayExt;
554 use crate::arrays::listview::ListViewArraySlotsExt;
555 use crate::assert_arrays_eq;
556 use crate::builders::ArrayBuilder;
557 use crate::builders::listview::PrimitiveArray;
558 use crate::dtype::DType;
559 use crate::dtype::Nullability::NonNullable;
560 use crate::dtype::Nullability::Nullable;
561 use crate::dtype::PType::I32;
562 use crate::scalar::Scalar;
563 use crate::validity::Validity;
564
565 #[test]
566 fn test_empty() {
567 let mut builder =
568 ListViewBuilder::<u32, u32>::with_capacity(Arc::new(I32.into()), NonNullable, 0, 0);
569
570 let listview = builder.finish();
571 assert_eq!(listview.len(), 0);
572 }
573
574 #[test]
575 fn test_basic_append_and_nulls() {
576 let mut ctx = array_session().create_execution_ctx();
577 let dtype: Arc<DType> = Arc::new(I32.into());
578 let mut builder =
579 ListViewBuilder::<u32, u32>::with_capacity(Arc::clone(&dtype), Nullable, 0, 0);
580
581 builder
583 .append_value(
584 Scalar::list(
585 Arc::clone(&dtype),
586 vec![1i32.into(), 2i32.into(), 3i32.into()],
587 NonNullable,
588 )
589 .as_list(),
590 )
591 .unwrap();
592
593 builder
595 .append_value(Scalar::list_empty(Arc::clone(&dtype), NonNullable).as_list())
596 .unwrap();
597
598 builder.append_null();
600
601 builder
603 .append_value(
604 Scalar::list(dtype, vec![4i32.into(), 5i32.into()], NonNullable).as_list(),
605 )
606 .unwrap();
607
608 let listview = builder.finish_into_listview();
609 assert_eq!(listview.len(), 4);
610
611 assert_arrays_eq!(
613 listview.list_elements_at(0).unwrap(),
614 PrimitiveArray::from_iter([1i32, 2, 3]),
615 &mut ctx
616 );
617
618 assert_eq!(listview.list_elements_at(1).unwrap().len(), 0);
620
621 assert!(
623 !listview
624 .validity()
625 .vortex_expect("listview validity should be derivable")
626 .execute_is_valid(2, &mut ctx)
627 .unwrap()
628 );
629
630 assert_arrays_eq!(
632 listview.list_elements_at(3).unwrap(),
633 PrimitiveArray::from_iter([4i32, 5]),
634 &mut ctx
635 );
636 }
637
638 #[test]
639 fn test_different_offset_size_types() {
640 let mut ctx = array_session().create_execution_ctx();
641 let dtype: Arc<DType> = Arc::new(I32.into());
643 let mut builder =
644 ListViewBuilder::<u64, u32>::with_capacity(Arc::clone(&dtype), NonNullable, 0, 0);
645
646 builder
647 .append_value(
648 Scalar::list(
649 Arc::clone(&dtype),
650 vec![1i32.into(), 2i32.into()],
651 NonNullable,
652 )
653 .as_list(),
654 )
655 .unwrap();
656
657 builder
658 .append_value(
659 Scalar::list(
660 dtype,
661 vec![3i32.into(), 4i32.into(), 5i32.into()],
662 NonNullable,
663 )
664 .as_list(),
665 )
666 .unwrap();
667
668 let listview = builder.finish_into_listview();
669 assert_eq!(listview.len(), 2);
670
671 assert_arrays_eq!(
673 listview.list_elements_at(0).unwrap(),
674 PrimitiveArray::from_iter([1i32, 2]),
675 &mut ctx
676 );
677
678 assert_arrays_eq!(
680 listview.list_elements_at(1).unwrap(),
681 PrimitiveArray::from_iter([3i32, 4, 5]),
682 &mut ctx
683 );
684
685 let dtype2: Arc<DType> = Arc::new(I32.into());
687 let mut builder2 =
688 ListViewBuilder::<i64, i32>::with_capacity(Arc::clone(&dtype2), NonNullable, 0, 0);
689
690 for i in 0..5 {
691 builder2
692 .append_value(
693 Scalar::list(Arc::clone(&dtype2), vec![(i * 10).into()], NonNullable).as_list(),
694 )
695 .unwrap();
696 }
697
698 let listview2 = builder2.finish_into_listview();
699 assert_eq!(listview2.len(), 5);
700
701 for i in 0..5i32 {
703 assert_arrays_eq!(
704 listview2.list_elements_at(i as usize).unwrap(),
705 PrimitiveArray::from_iter([i * 10]),
706 &mut ctx
707 );
708 }
709 }
710
711 #[test]
712 fn test_builder_trait_methods() {
713 let mut ctx = array_session().create_execution_ctx();
714 let dtype: Arc<DType> = Arc::new(I32.into());
715 let mut builder =
716 ListViewBuilder::<u32, u32>::with_capacity(Arc::clone(&dtype), Nullable, 0, 0);
717
718 builder.append_zeros(2);
720 assert_eq!(builder.len(), 2);
721
722 unsafe {
724 builder.append_nulls_unchecked(2);
725 }
726 assert_eq!(builder.len(), 4);
727
728 let list_scalar = Scalar::list(dtype, vec![10i32.into(), 20i32.into()], Nullable);
730 builder.append_scalar(&list_scalar).unwrap();
731 assert_eq!(builder.len(), 5);
732
733 let listview = builder.finish_into_listview();
734 assert_eq!(listview.len(), 5);
735
736 assert_eq!(listview.list_elements_at(0).unwrap().len(), 0);
738 assert_eq!(listview.list_elements_at(1).unwrap().len(), 0);
739
740 assert!(
742 !listview
743 .validity()
744 .vortex_expect("listview validity should be derivable")
745 .execute_is_valid(2, &mut ctx)
746 .unwrap()
747 );
748 assert!(
749 !listview
750 .validity()
751 .vortex_expect("listview validity should be derivable")
752 .execute_is_valid(3, &mut ctx)
753 .unwrap()
754 );
755
756 assert_arrays_eq!(
758 listview.list_elements_at(4).unwrap(),
759 PrimitiveArray::from_iter([10i32, 20]),
760 &mut ctx
761 );
762 }
763
764 #[test]
765 fn test_extend_from_array() {
766 let mut ctx = array_session().create_execution_ctx();
767 let dtype: Arc<DType> = Arc::new(I32.into());
768
769 let source = ListArray::from_iter_opt_slow::<u32, _, Vec<i32>>(
771 [Some(vec![1, 2, 3]), None, Some(vec![4, 5])],
772 Arc::new(I32.into()),
773 )
774 .unwrap();
775
776 let mut builder =
777 ListViewBuilder::<u32, u32>::with_capacity(Arc::clone(&dtype), Nullable, 0, 0);
778
779 builder
781 .append_value(Scalar::list(dtype, vec![0i32.into()], NonNullable).as_list())
782 .unwrap();
783
784 let source = source
786 .into_array()
787 .execute::<ListViewArray>(&mut ctx)
788 .unwrap();
789 builder
790 .append_listview_array(source.as_view(), &mut ctx)
791 .unwrap();
792
793 let empty_source = ListArray::from_iter_opt_slow::<u32, _, Vec<i32>>(
795 std::iter::empty::<Option<Vec<i32>>>(),
796 Arc::new(I32.into()),
797 )
798 .unwrap();
799 let empty_source = empty_source
800 .into_array()
801 .execute::<ListViewArray>(&mut ctx)
802 .unwrap();
803 builder
804 .append_listview_array(empty_source.as_view(), &mut ctx)
805 .unwrap();
806
807 let listview = builder.finish_into_listview();
808 assert_eq!(listview.len(), 4);
809
810 assert_arrays_eq!(
813 listview.list_elements_at(0).unwrap(),
814 PrimitiveArray::from_iter([0i32]),
815 &mut ctx
816 );
817
818 assert_arrays_eq!(
820 listview.list_elements_at(1).unwrap(),
821 PrimitiveArray::from_iter([1i32, 2, 3]),
822 &mut ctx
823 );
824
825 assert!(
827 !listview
828 .validity()
829 .vortex_expect("listview validity should be derivable")
830 .execute_is_valid(2, &mut ctx)
831 .unwrap()
832 );
833
834 assert_arrays_eq!(
836 listview.list_elements_at(3).unwrap(),
837 PrimitiveArray::from_iter([4i32, 5]),
838 &mut ctx
839 );
840 }
841
842 #[test]
843 fn test_append_list_array_grows_builder() -> VortexResult<()> {
844 let mut ctx = array_session().create_execution_ctx();
845 let dtype: Arc<DType> = Arc::new(I32.into());
846
847 let lists: Vec<Option<Vec<i32>>> =
850 (0..100).map(|i| (i % 10 != 0).then(|| vec![i])).collect();
851 let source = ListArray::from_iter_opt_slow::<u32, _, _>(lists.clone(), Arc::clone(&dtype))?;
852
853 let mut builder =
854 ListViewBuilder::<u32, u32>::with_capacity(Arc::clone(&dtype), Nullable, 0, 0);
855 builder.append_list_array(source.as_view(), &mut ctx)?;
856 builder.append_list_array(source.as_view(), &mut ctx)?;
858
859 let listview = builder.finish_into_listview();
860 assert!(listview.is_zero_copy_to_list());
861
862 let expected = ListArray::from_iter_opt_slow::<u32, _, _>(
863 lists.iter().cloned().chain(lists.iter().cloned()),
864 dtype,
865 )?;
866 assert_arrays_eq!(listview, expected, &mut ctx);
867
868 Ok(())
869 }
870
871 #[test]
874 fn test_constant_list_append_keeps_one_copy_of_the_value() -> VortexResult<()> {
875 let mut ctx = array_session().create_execution_ctx();
876 let element_dtype: Arc<DType> = Arc::new(I32.into());
877
878 const ROWS: usize = 10_000;
879 let fill = Scalar::list(
880 Arc::clone(&element_dtype),
881 vec![1i32.into(), 2i32.into(), 3i32.into()],
882 NonNullable,
883 );
884 let constant = ConstantArray::new(fill, ROWS).into_array();
885
886 let mut builder =
887 ListViewBuilder::<u64, u64>::with_capacity(element_dtype, NonNullable, 0, 0);
888 constant.append_to_builder(&mut builder, &mut ctx)?;
889 let listview = builder.finish_into_listview();
890
891 assert_eq!(listview.len(), ROWS);
892 assert_eq!(
893 listview.elements().len(),
894 3,
895 "the fill value should be stored once, not once per row",
896 );
897 assert!(!listview.is_zero_copy_to_list());
898 assert_arrays_eq!(&listview.into_array(), &constant, &mut ctx);
899
900 Ok(())
901 }
902
903 #[test]
904 fn test_extend_from_array_overlapping_listview() {
905 let mut ctx = array_session().create_execution_ctx();
906 let dtype: Arc<DType> = Arc::new(I32.into());
907
908 let source = unsafe {
913 ListViewArray::new_unchecked(
914 buffer![10i32, 20, 30].into_array(),
915 buffer![0u32, 1, 0].into_array(),
916 buffer![2u8, 2, 1].into_array(),
917 Validity::from_iter([true, false, true]),
918 )
919 };
920 assert!(!source.is_zero_copy_to_list());
921
922 let mut builder =
923 ListViewBuilder::<u32, u32>::with_capacity(Arc::clone(&dtype), Nullable, 0, 0);
924 builder
925 .append_listview_array(source.as_view(), &mut ctx)
926 .unwrap();
927
928 let listview = builder.finish_into_listview();
929 assert_eq!(listview.len(), 3);
930 assert!(!listview.is_zero_copy_to_list());
932
933 assert_arrays_eq!(
934 listview.list_elements_at(0).unwrap(),
935 PrimitiveArray::from_iter([10i32, 20]),
936 &mut ctx
937 );
938 assert!(
939 !listview
940 .validity()
941 .vortex_expect("listview validity should be derivable")
942 .execute_is_valid(1, &mut ctx)
943 .unwrap()
944 );
945 assert_eq!(listview.size_at(1), source.size_at(1));
947 assert_arrays_eq!(
948 listview.list_elements_at(2).unwrap(),
949 PrimitiveArray::from_iter([10i32]),
950 &mut ctx
951 );
952 }
953
954 #[test]
955 fn test_error_append_null_to_non_nullable() {
956 let dtype: Arc<DType> = Arc::new(I32.into());
957 let mut builder =
958 ListViewBuilder::<u32, u32>::with_capacity(Arc::clone(&dtype), NonNullable, 0, 0);
959
960 let null_scalar = Scalar::null(DType::List(dtype, Nullable));
962 let null_list = null_scalar.as_list();
963
964 let result = builder.append_value(null_list);
966 assert!(result.is_err());
967 assert!(
968 result
969 .unwrap_err()
970 .to_string()
971 .contains("null value to non-nullable")
972 );
973 }
974
975 #[test]
976 fn test_append_array_as_list() {
977 let dtype: Arc<DType> = Arc::new(I32.into());
978 let mut ctx = array_session().create_execution_ctx();
979 let mut builder =
980 ListViewBuilder::<u32, u32>::with_capacity(Arc::clone(&dtype), NonNullable, 20, 10);
981
982 let arr1 = buffer![1i32, 2, 3].into_array();
984 builder.append_array_as_list(&arr1, &mut ctx).unwrap();
985
986 builder
988 .append_value(
989 Scalar::list(
990 Arc::clone(&dtype),
991 vec![10i32.into(), 11i32.into()],
992 NonNullable,
993 )
994 .as_list(),
995 )
996 .unwrap();
997
998 let arr2 = buffer![4i32, 5].into_array();
1000 builder.append_array_as_list(&arr2, &mut ctx).unwrap();
1001
1002 let arr3 = buffer![0i32; 0].into_array();
1004 builder.append_array_as_list(&arr3, &mut ctx).unwrap();
1005
1006 builder
1008 .append_value(Scalar::list_empty(Arc::clone(&dtype), NonNullable).as_list())
1009 .unwrap();
1010
1011 let listview = builder.finish_into_listview();
1012 assert_eq!(listview.len(), 5);
1013
1014 assert_arrays_eq!(
1016 listview.elements(),
1017 PrimitiveArray::from_iter([1i32, 2, 3, 10, 11, 4, 5]),
1018 &mut ctx
1019 );
1020
1021 assert_arrays_eq!(
1023 listview.offsets(),
1024 PrimitiveArray::from_iter([0u32, 3, 5, 7, 7]),
1025 &mut ctx
1026 );
1027
1028 assert_arrays_eq!(
1030 listview.sizes(),
1031 PrimitiveArray::from_iter([3u32, 2, 2, 0, 0]),
1032 &mut ctx
1033 );
1034
1035 let mut builder = ListViewBuilder::<u32, u32>::with_capacity(dtype, NonNullable, 20, 10);
1037 let wrong_dtype_arr = buffer![1i64, 2, 3].into_array();
1038 assert!(
1039 builder
1040 .append_array_as_list(&wrong_dtype_arr, &mut ctx)
1041 .is_err()
1042 );
1043 }
1044}