1use vortex_buffer::BufferAllocatorRef;
5use vortex_error::VortexExpect;
6use vortex_error::VortexResult;
7
8use crate::ArrayRef;
9use crate::Canonical;
10use crate::ExecutionCtx;
11use crate::IntoArray;
12use crate::arrays::ExtensionArray;
13use crate::arrays::FixedSizeListArray;
14use crate::arrays::ListArray;
15use crate::arrays::ListViewArray;
16use crate::arrays::PrimitiveArray;
17use crate::arrays::StructArray;
18use crate::arrays::extension::ExtensionArrayExt;
19use crate::arrays::fixed_size_list::FixedSizeListArrayExt;
20use crate::arrays::fixed_size_list::FixedSizeListArraySlotsExt;
21use crate::arrays::list::ListArrayExt;
22use crate::arrays::list::ListArraySlotsExt;
23use crate::arrays::listview::ListViewArrayExt;
24use crate::arrays::listview::ListViewArraySlotsExt;
25use crate::arrays::listview::ListViewRebuildMode;
26use crate::arrays::struct_::StructArrayExt;
27use crate::builders::PrimitiveBuilder;
28use crate::dtype::IntegerPType;
29use crate::dtype::Nullability;
30use crate::match_each_integer_ptype;
31
32pub fn list_view_from_list(list: ListArray, ctx: &mut ExecutionCtx) -> VortexResult<ListViewArray> {
37 if list.is_empty() {
40 return Ok(Canonical::empty(list.dtype()).into_listview());
41 }
42
43 let list = list.reset_offsets(false, ctx)?;
47
48 let list_offsets = list.offsets().clone().execute::<PrimitiveArray>(ctx)?;
51
52 let sizes = match_each_integer_ptype!(list_offsets.ptype(), |O| {
55 build_sizes_from_offsets::<O>(&list_offsets, ctx.allocator())?
56 });
57
58 debug_assert_eq!(list_offsets.len(), list.len() + 1);
60 let adjusted_offsets = list_offsets.into_array().slice(0..list.len())?;
61
62 Ok(unsafe {
66 ListViewArray::new_unchecked(
67 list.elements().clone(),
68 adjusted_offsets,
69 sizes,
70 list.validity()?,
71 )
72 .with_zero_copy_to_list(true)
73 })
74}
75
76fn build_sizes_from_offsets<O: IntegerPType>(
80 offsets: &PrimitiveArray,
81 allocator: &BufferAllocatorRef,
82) -> VortexResult<ArrayRef> {
83 let offsets_slice = offsets.as_slice::<O>();
84 debug_assert!(offsets_slice.is_sorted());
85
86 let len = offsets_slice.len() - 1;
87 let mut sizes_builder =
88 PrimitiveBuilder::<O>::with_capacity_in(Nullability::NonNullable, len, allocator);
89
90 let mut sizes_range = sizes_builder.uninit_range(len);
92
93 for i in 0..len {
95 let size = offsets_slice[i + 1] - offsets_slice[i];
96 sizes_range.set_value(i, size);
97 }
98
99 unsafe {
101 sizes_range.finish();
102 }
103
104 Ok(sizes_builder.finish_into_primitive().into_array())
105}
106
107pub fn list_from_list_view(
116 list_view: ListViewArray,
117 ctx: &mut ExecutionCtx,
118) -> VortexResult<ListArray> {
119 let zctl_array = list_view.rebuild(ListViewRebuildMode::MakeExact, ctx)?;
121 debug_assert!(zctl_array.is_zero_copy_to_list());
122
123 let list_offsets = match_each_integer_ptype!(zctl_array.offsets().dtype().as_ptype(), |O| {
124 unsafe { build_list_offsets_from_list_view::<O>(&zctl_array, ctx) }
127 });
128
129 Ok(unsafe {
133 ListArray::new_unchecked(
134 zctl_array.elements().clone(),
135 list_offsets,
136 zctl_array.validity()?,
137 )
138 })
139}
140
141unsafe fn build_list_offsets_from_list_view<O: IntegerPType>(
152 list_view: &ListViewArray,
153 ctx: &mut ExecutionCtx,
154) -> ArrayRef {
155 let len = list_view.len();
156 let mut offsets_builder =
157 PrimitiveBuilder::<O>::with_capacity_in(Nullability::NonNullable, len + 1, ctx.allocator());
158
159 let mut offsets_range = offsets_builder.uninit_range(len + 1);
161
162 let offsets = list_view
163 .offsets()
164 .clone()
165 .execute::<PrimitiveArray>(ctx)
166 .vortex_expect("list view offsets must be primitive after rebuild");
167 let offsets_slice = offsets.as_slice::<O>();
168 debug_assert!(offsets_slice.is_sorted());
169
170 offsets_range.copy_from_slice(0, offsets_slice);
172
173 let final_offset = if len != 0 {
175 let last_offset = offsets_slice[len - 1];
176
177 let last_size = list_view.size_at(len - 1);
178 let last_size =
179 O::from_usize(last_size).vortex_expect("size somehow did not fit into offsets");
180
181 last_offset + last_size
182 } else {
183 O::zero()
184 };
185
186 offsets_range.set_value(len, final_offset);
187
188 unsafe {
190 offsets_range.finish();
191 }
192
193 offsets_builder.finish_into_primitive().into_array()
194}
195
196pub fn recursive_list_from_list_view(
200 array: ArrayRef,
201 ctx: &mut ExecutionCtx,
202) -> VortexResult<ArrayRef> {
203 if !array.dtype().is_nested() {
204 return Ok(array);
205 }
206
207 let canonical = array.execute::<Canonical>(ctx)?;
208
209 Ok(match canonical {
210 Canonical::List(listview) => {
211 let converted_elements =
212 recursive_list_from_list_view(listview.elements().clone(), ctx)?;
213 debug_assert_eq!(converted_elements.len(), listview.elements().len());
214
215 let listview_with_converted_elements =
217 if !ArrayRef::ptr_eq(&converted_elements, listview.elements()) {
218 unsafe {
221 ListViewArray::new_unchecked(
222 converted_elements,
223 listview.offsets().clone(),
224 listview.sizes().clone(),
225 listview.validity()?,
226 )
227 .with_zero_copy_to_list(listview.is_zero_copy_to_list())
228 }
229 } else {
230 listview
231 };
232
233 let list_array = list_from_list_view(listview_with_converted_elements, ctx)?;
235 list_array.into_array()
236 }
237 Canonical::FixedSizeList(fixed_size_list) => {
238 let converted_elements =
239 recursive_list_from_list_view(fixed_size_list.elements().clone(), ctx)?;
240
241 if !ArrayRef::ptr_eq(&converted_elements, fixed_size_list.elements()) {
243 FixedSizeListArray::try_new(
244 converted_elements,
245 fixed_size_list.list_size(),
246 fixed_size_list.validity()?,
247 fixed_size_list.len(),
248 )
249 .vortex_expect(
250 "FixedSizeListArray reconstruction should not fail with valid components",
251 )
252 .into_array()
253 } else {
254 fixed_size_list.into_array()
255 }
256 }
257 Canonical::Struct(struct_array) => {
258 let mut converted_fields =
259 Vec::with_capacity(struct_array.iter_unmasked_fields().len());
260 let mut any_changed = false;
261
262 for field in struct_array.iter_unmasked_fields() {
263 let converted_field = recursive_list_from_list_view(field.clone(), ctx)?;
264 any_changed |= !ArrayRef::ptr_eq(&converted_field, field);
266 converted_fields.push(converted_field);
267 }
268
269 if any_changed {
270 StructArray::try_new(
271 struct_array.names().clone(),
272 converted_fields,
273 struct_array.len(),
274 struct_array.validity()?,
275 )
276 .vortex_expect("StructArray reconstruction should not fail with valid components")
277 .into_array()
278 } else {
279 struct_array.into_array()
280 }
281 }
282 Canonical::Extension(ext_array) => {
283 let converted_storage =
284 recursive_list_from_list_view(ext_array.storage_array().clone(), ctx)?;
285
286 if !ArrayRef::ptr_eq(&converted_storage, ext_array.storage_array()) {
288 ExtensionArray::new(ext_array.ext_dtype().clone(), converted_storage).into_array()
289 } else {
290 ext_array.into_array()
291 }
292 }
293 _ => unreachable!(),
294 })
295}
296
297#[cfg(test)]
298mod tests {
299
300 use vortex_buffer::buffer;
301 use vortex_error::VortexExpect;
302 use vortex_error::VortexResult;
303
304 use super::super::tests::common::SESSION;
305 use super::super::tests::common::create_basic_listview;
306 use super::super::tests::common::create_empty_lists_listview;
307 use super::super::tests::common::create_nullable_listview;
308 use super::super::tests::common::create_overlapping_listview;
309 use super::recursive_list_from_list_view;
310 use crate::ArrayEq;
311 use crate::ArrayRef;
312 use crate::EqMode;
313 use crate::IntoArray;
314 use crate::VortexSessionExecute;
315 use crate::arrays::BoolArray;
316 use crate::arrays::FixedSizeList;
317 use crate::arrays::FixedSizeListArray;
318 use crate::arrays::List;
319 use crate::arrays::ListArray;
320 use crate::arrays::ListViewArray;
321 use crate::arrays::PrimitiveArray;
322 use crate::arrays::Struct;
323 use crate::arrays::StructArray;
324 use crate::arrays::VarBinViewArray;
325 use crate::arrays::fixed_size_list::FixedSizeListArraySlotsExt;
326 use crate::arrays::list::ListArrayExt;
327 use crate::arrays::list::ListArraySlotsExt;
328 use crate::arrays::listview::ListViewArraySlotsExt;
329 use crate::arrays::listview::list_from_list_view;
330 use crate::arrays::listview::list_view_from_list;
331 use crate::arrays::struct_::StructArrayExt;
332 use crate::assert_arrays_eq;
333 use crate::dtype::FieldNames;
334 use crate::validity::Validity;
335
336 #[test]
337 fn test_list_to_listview_basic() -> VortexResult<()> {
338 let elements = buffer![0i32, 1, 2, 3, 4, 5, 6, 7, 8, 9].into_array();
340 let offsets = buffer![0u32, 3, 5, 7, 10].into_array();
341 let list_array = ListArray::try_new(elements.clone(), offsets, Validity::NonNullable)?;
342
343 let mut ctx = SESSION.create_execution_ctx();
344 let list_view = list_view_from_list(list_array.clone(), &mut ctx)?;
345
346 assert_eq!(list_view.len(), 4);
348 assert_arrays_eq!(list_view.elements().clone(), elements, &mut ctx);
349
350 let expected_offsets = buffer![0u32, 3, 5, 7].into_array();
352 assert_arrays_eq!(list_view.offsets().clone(), expected_offsets, &mut ctx);
353
354 let expected_sizes = buffer![3u32, 2, 2, 3].into_array();
356 assert_arrays_eq!(list_view.sizes().clone(), expected_sizes, &mut ctx);
357
358 assert_arrays_eq!(list_view, list_array, &mut ctx);
360 Ok(())
361 }
362
363 #[test]
364 fn test_list_to_listview_resets_nonzero_offsets() -> VortexResult<()> {
365 let elements = buffer![0i32, 1, 2, 3, 4].into_array();
366 let offsets = buffer![2u16, 4, 5].into_array();
367 let list = ListArray::try_new(elements, offsets, Validity::NonNullable)?;
368
369 let mut ctx = SESSION.create_execution_ctx();
370 let list_view = list_view_from_list(list.clone(), &mut ctx)?;
371
372 assert_arrays_eq!(
373 list_view.offsets().clone(),
374 buffer![0u16, 2].into_array(),
375 &mut ctx
376 );
377 assert_arrays_eq!(list_view, list, &mut ctx);
378 Ok(())
379 }
380
381 #[test]
382 fn test_listview_to_list_zero_copy() -> VortexResult<()> {
383 let mut ctx = SESSION.create_execution_ctx();
384 let list_view = create_basic_listview();
385 let list_array =
386 list_from_list_view(list_view.clone(), &mut SESSION.create_execution_ctx())?;
387
388 assert_arrays_eq!(
390 list_array.elements().clone(),
391 list_view.elements().clone(),
392 &mut ctx
393 );
394
395 let list_array_offsets_without_last = list_array.offsets().slice(0..list_view.len())?;
398 assert_arrays_eq!(
399 list_array_offsets_without_last,
400 list_view.offsets().clone(),
401 &mut ctx
402 );
403
404 assert_arrays_eq!(list_array, list_view, &mut ctx);
406 Ok(())
407 }
408
409 #[test]
410 fn test_empty_array_conversions() -> VortexResult<()> {
411 let empty_elements = PrimitiveArray::from_iter::<[i32; 0]>([]).into_array();
413 let empty_offsets = buffer![0u32].into_array();
414 let empty_list = ListArray::try_new(empty_elements, empty_offsets, Validity::NonNullable)?;
415
416 let mut ctx = SESSION.create_execution_ctx();
419 let empty_list_view = list_view_from_list(empty_list.clone(), &mut ctx)?;
420 assert_eq!(empty_list_view.len(), 0);
421
422 assert_arrays_eq!(empty_list_view, empty_list, &mut ctx);
424 let converted_back = list_from_list_view(empty_list_view, &mut ctx)?;
425 assert_eq!(converted_back.len(), 0);
426 assert_arrays_eq!(converted_back, empty_list, &mut ctx);
427 Ok(())
428 }
429
430 #[test]
431 fn test_nullable_conversions() -> VortexResult<()> {
432 let elements = buffer![10i32, 20, 30, 40, 50].into_array();
434 let offsets = buffer![0u32, 2, 4, 5].into_array();
435 let validity = Validity::Array(BoolArray::from_iter(vec![true, false, true]).into_array());
436 let nullable_list = ListArray::try_new(elements, offsets, validity.clone())?;
437
438 let mut ctx = SESSION.create_execution_ctx();
439 let nullable_list_view = list_view_from_list(nullable_list.clone(), &mut ctx)?;
440
441 assert!(
443 nullable_list_view
444 .validity()
445 .vortex_expect("listview validity should be derivable")
446 .array_eq(&validity, EqMode::Ptr)
447 );
448 assert_eq!(nullable_list_view.len(), 3);
449
450 let converted_back = list_from_list_view(nullable_list_view, &mut ctx)?;
452 assert_arrays_eq!(converted_back, nullable_list, &mut ctx);
453 Ok(())
454 }
455
456 #[test]
457 fn test_non_zero_copy_listview_to_list() -> VortexResult<()> {
458 let mut ctx = SESSION.create_execution_ctx();
459 let list_view = create_overlapping_listview();
461 let list_array =
462 list_from_list_view(list_view.clone(), &mut SESSION.create_execution_ctx())?;
463
464 for i in 0..list_array.len() {
466 let start = list_array.offset_at(i)?;
467 let end = list_array.offset_at(i + 1)?;
468 assert!(end >= start, "Offsets should be monotonic after conversion");
469 }
470
471 assert_arrays_eq!(list_array, list_view, &mut ctx);
473 Ok(())
474 }
475
476 #[test]
477 fn test_empty_sublists() -> VortexResult<()> {
478 let mut ctx = SESSION.create_execution_ctx();
479 let empty_lists_view = create_empty_lists_listview();
480
481 let list_array = list_from_list_view(empty_lists_view.clone(), &mut ctx)?;
483 assert_eq!(list_array.len(), 4);
484
485 for i in 0..list_array.len() {
487 assert_eq!(list_array.list_elements_at(i)?.len(), 0);
488 }
489
490 let converted_back = list_view_from_list(list_array, &mut ctx)?;
492 assert_arrays_eq!(converted_back, empty_lists_view, &mut ctx);
493 Ok(())
494 }
495
496 #[test]
497 fn test_different_offset_types() -> VortexResult<()> {
498 let elements = buffer![1i32, 2, 3, 4, 5].into_array();
500 let i32_offsets = buffer![0i32, 2, 5].into_array();
501 let list_i32 =
502 ListArray::try_new(elements.clone(), i32_offsets.clone(), Validity::NonNullable)?;
503
504 let mut ctx = SESSION.create_execution_ctx();
505 let list_view_i32 = list_view_from_list(list_i32.clone(), &mut ctx)?;
506 assert_eq!(list_view_i32.offsets().dtype(), i32_offsets.dtype());
507 assert_eq!(list_view_i32.sizes().dtype(), i32_offsets.dtype());
508
509 let i64_offsets = buffer![0i64, 2, 5].into_array();
511 let list_i64 = ListArray::try_new(elements, i64_offsets.clone(), Validity::NonNullable)?;
512
513 let list_view_i64 = list_view_from_list(list_i64.clone(), &mut ctx)?;
514 assert_eq!(list_view_i64.offsets().dtype(), i64_offsets.dtype());
515 assert_eq!(list_view_i64.sizes().dtype(), i64_offsets.dtype());
516
517 assert_arrays_eq!(list_view_i32, list_i32, &mut ctx);
519 assert_arrays_eq!(list_view_i64, list_i64, &mut ctx);
520 Ok(())
521 }
522
523 #[test]
524 fn test_round_trip_conversions() -> VortexResult<()> {
525 let mut ctx = SESSION.create_execution_ctx();
526
527 let original = create_basic_listview();
529 let to_list = list_from_list_view(original.clone(), &mut ctx)?;
530 let back_to_view = list_view_from_list(to_list, &mut ctx)?;
531 assert_arrays_eq!(back_to_view, original, &mut ctx);
532
533 let nullable = create_nullable_listview();
535 let nullable_to_list = list_from_list_view(nullable.clone(), &mut ctx)?;
536 let nullable_back = list_view_from_list(nullable_to_list, &mut ctx)?;
537 assert_arrays_eq!(nullable_back, nullable, &mut ctx);
538
539 let overlapping = create_overlapping_listview();
541
542 let overlapping_to_list = list_from_list_view(overlapping.clone(), &mut ctx)?;
543 let overlapping_back = list_view_from_list(overlapping_to_list, &mut ctx)?;
544 assert_arrays_eq!(overlapping_back, overlapping, &mut ctx);
545 Ok(())
546 }
547
548 #[test]
549 fn test_single_element_lists() -> VortexResult<()> {
550 let elements = buffer![100i32, 200, 300].into_array();
552 let offsets = buffer![0u32, 1, 2, 3].into_array();
553 let single_elem_list = ListArray::try_new(elements, offsets, Validity::NonNullable)?;
554
555 let mut ctx = SESSION.create_execution_ctx();
556 let list_view = list_view_from_list(single_elem_list.clone(), &mut ctx)?;
557 assert_eq!(list_view.len(), 3);
558
559 let expected_sizes = buffer![1u32, 1, 1].into_array();
561 assert_arrays_eq!(list_view.sizes().clone(), expected_sizes, &mut ctx);
562
563 let converted_back = list_from_list_view(list_view, &mut ctx)?;
565 assert_arrays_eq!(converted_back, single_elem_list, &mut ctx);
566 Ok(())
567 }
568
569 #[test]
570 fn test_mixed_empty_and_non_empty_lists() -> VortexResult<()> {
571 let elements = buffer![1i32, 2, 3, 4, 5, 6].into_array();
573 let offsets = buffer![0u32, 2, 2, 3, 3, 6].into_array();
574 let mixed_list = ListArray::try_new(elements, offsets, Validity::NonNullable)?;
575
576 let mut ctx = SESSION.create_execution_ctx();
577 let list_view = list_view_from_list(mixed_list.clone(), &mut ctx)?;
578 assert_eq!(list_view.len(), 5);
579
580 let expected_sizes = buffer![2u32, 0, 1, 0, 3].into_array();
582 assert_arrays_eq!(list_view.sizes().clone(), expected_sizes, &mut ctx);
583
584 let converted_back = list_from_list_view(list_view, &mut ctx)?;
586 assert_arrays_eq!(converted_back, mixed_list, &mut ctx);
587 Ok(())
588 }
589
590 #[test]
591 fn test_recursive_simple_listview() -> VortexResult<()> {
592 let mut ctx = SESSION.create_execution_ctx();
593 let list_view = create_basic_listview();
594 let result = recursive_list_from_list_view(
595 list_view.clone().into_array(),
596 &mut SESSION.create_execution_ctx(),
597 )?;
598
599 assert!(result.is::<List>());
600 assert_eq!(result.len(), list_view.len());
601 assert_arrays_eq!(result, list_view.into_array(), &mut ctx);
602 Ok(())
603 }
604
605 #[test]
606 fn test_recursive_nested_listview() -> VortexResult<()> {
607 let mut ctx = SESSION.create_execution_ctx();
608 let inner_elements = buffer![1i32, 2, 3].into_array();
609 let inner_offsets = buffer![0u32, 2].into_array();
610 let inner_sizes = buffer![2u32, 1].into_array();
611 let inner_listview = unsafe {
612 ListViewArray::new_unchecked(
613 inner_elements,
614 inner_offsets,
615 inner_sizes,
616 Validity::NonNullable,
617 )
618 .with_zero_copy_to_list(true)
619 };
620
621 let outer_offsets = buffer![0u32, 1].into_array();
622 let outer_sizes = buffer![1u32, 1].into_array();
623 let outer_listview = unsafe {
624 ListViewArray::new_unchecked(
625 inner_listview.into_array(),
626 outer_offsets,
627 outer_sizes,
628 Validity::NonNullable,
629 )
630 .with_zero_copy_to_list(true)
631 };
632
633 let result = recursive_list_from_list_view(
634 outer_listview.clone().into_array(),
635 &mut SESSION.create_execution_ctx(),
636 )?;
637
638 assert!(result.as_::<List>().elements().is::<List>());
639 assert_eq!(result.len(), 2);
640 assert_arrays_eq!(result, outer_listview.into_array(), &mut ctx);
641 Ok(())
642 }
643
644 #[test]
645 fn test_recursive_struct_with_listview_fields() -> VortexResult<()> {
646 let mut ctx = SESSION.create_execution_ctx();
647 let listview_field = create_basic_listview().into_array();
648 let primitive_field = buffer![10i32, 20, 30, 40].into_array();
649
650 let struct_array = StructArray::try_new(
651 FieldNames::from(["lists", "values"]),
652 vec![listview_field, primitive_field],
653 4,
654 Validity::NonNullable,
655 )?;
656
657 let result = recursive_list_from_list_view(
658 struct_array.clone().into_array(),
659 &mut SESSION.create_execution_ctx(),
660 )?;
661
662 assert!(
663 result
664 .as_::<Struct>()
665 .unmasked_field_by_name("lists")?
666 .is::<List>()
667 );
668 assert_eq!(result.len(), 4);
669 assert_arrays_eq!(result, struct_array.into_array(), &mut ctx);
670 Ok(())
671 }
672
673 #[test]
674 fn test_recursive_fixed_size_list_with_listview_elements() -> VortexResult<()> {
675 let mut ctx = SESSION.create_execution_ctx();
676 let lv1_elements = buffer![1i32, 2].into_array();
677 let lv1_offsets = buffer![0u32].into_array();
678 let lv1_sizes = buffer![2u32].into_array();
679 let lv1 = unsafe {
680 ListViewArray::new_unchecked(
681 lv1_elements,
682 lv1_offsets,
683 lv1_sizes,
684 Validity::NonNullable,
685 )
686 .with_zero_copy_to_list(true)
687 };
688
689 let lv2_elements = buffer![3i32, 4].into_array();
690 let lv2_offsets = buffer![0u32].into_array();
691 let lv2_sizes = buffer![2u32].into_array();
692 let lv2 = unsafe {
693 ListViewArray::new_unchecked(
694 lv2_elements,
695 lv2_offsets,
696 lv2_sizes,
697 Validity::NonNullable,
698 )
699 .with_zero_copy_to_list(true)
700 };
701
702 let dtype = lv1.dtype().clone();
703 let chunked_listviews =
704 crate::arrays::ChunkedArray::try_new(vec![lv1.into_array(), lv2.into_array()], dtype)?;
705
706 let fixed_list =
707 FixedSizeListArray::new(chunked_listviews.into_array(), 1, Validity::NonNullable, 2);
708
709 let result = recursive_list_from_list_view(
710 fixed_list.clone().into_array(),
711 &mut SESSION.create_execution_ctx(),
712 )?;
713
714 assert!(result.as_::<FixedSizeList>().elements().is::<List>());
715 assert_eq!(result.len(), 2);
716 assert_arrays_eq!(result, fixed_list.into_array(), &mut ctx);
717 Ok(())
718 }
719
720 #[test]
721 fn test_recursive_deep_nesting() -> VortexResult<()> {
722 let mut ctx = SESSION.create_execution_ctx();
723 let innermost_elements = buffer![1i32, 2, 3].into_array();
724 let innermost_offsets = buffer![0u32, 2].into_array();
725 let innermost_sizes = buffer![2u32, 1].into_array();
726 let innermost_listview = unsafe {
727 ListViewArray::new_unchecked(
728 innermost_elements,
729 innermost_offsets,
730 innermost_sizes,
731 Validity::NonNullable,
732 )
733 .with_zero_copy_to_list(true)
734 };
735
736 let struct_array = StructArray::try_new(
737 FieldNames::from(["inner_lists"]),
738 vec![innermost_listview.into_array()],
739 2,
740 Validity::NonNullable,
741 )?;
742
743 let outer_offsets = buffer![0u32, 1].into_array();
744 let outer_sizes = buffer![1u32, 1].into_array();
745 let outer_listview = unsafe {
746 ListViewArray::new_unchecked(
747 struct_array.into_array(),
748 outer_offsets,
749 outer_sizes,
750 Validity::NonNullable,
751 )
752 .with_zero_copy_to_list(true)
753 };
754
755 let result = recursive_list_from_list_view(
756 outer_listview.clone().into_array(),
757 &mut SESSION.create_execution_ctx(),
758 )?;
759
760 assert!(
761 result
762 .as_::<List>()
763 .elements()
764 .as_::<Struct>()
765 .unmasked_field_by_name("inner_lists")?
766 .is::<List>()
767 );
768 assert_eq!(result.len(), 2);
769 assert_arrays_eq!(result, outer_listview.into_array(), &mut ctx);
770 Ok(())
771 }
772
773 #[test]
774 fn test_recursive_primitive_unchanged() -> VortexResult<()> {
775 let prim = buffer![1i32, 2, 3].into_array();
776 let prim_clone = prim.clone();
777 let result = recursive_list_from_list_view(prim, &mut SESSION.create_execution_ctx())?;
778
779 assert!(ArrayRef::ptr_eq(&result, &prim_clone));
780 Ok(())
781 }
782
783 #[test]
784 fn test_recursive_mixed_listview_and_list() -> VortexResult<()> {
785 let mut ctx = SESSION.create_execution_ctx();
786 let listview = create_basic_listview();
787 let list = list_from_list_view(listview.clone(), &mut ctx)?;
788
789 let struct_array = StructArray::try_new(
790 FieldNames::from(["listview_field", "list_field"]),
791 vec![listview.into_array(), list.into_array()],
792 4,
793 Validity::NonNullable,
794 )?;
795
796 let result = recursive_list_from_list_view(struct_array.clone().into_array(), &mut ctx)?;
797
798 assert!(
799 result
800 .as_::<Struct>()
801 .unmasked_field_by_name("listview_field")?
802 .is::<List>()
803 );
804 assert!(
805 result
806 .as_::<Struct>()
807 .unmasked_field_by_name("list_field")?
808 .is::<List>()
809 );
810 assert_eq!(result.len(), 4);
811 assert_arrays_eq!(result, struct_array.into_array(), &mut ctx);
812 Ok(())
813 }
814
815 #[test]
821 fn test_empty_listview_to_list_without_zctl_flag() -> VortexResult<()> {
822 let elements = VarBinViewArray::from_iter_str(Vec::<&str>::new()).into_array();
823 let offsets = PrimitiveArray::from_iter(Vec::<i16>::new()).into_array();
824 let sizes = PrimitiveArray::from_iter(Vec::<i16>::new()).into_array();
825 let list_view = ListViewArray::try_new(elements, offsets, sizes, Validity::AllValid)?;
826
827 assert!(!list_view.is_zero_copy_to_list());
829
830 let list_array = list_from_list_view(list_view, &mut SESSION.create_execution_ctx())?;
831 assert_eq!(list_array.len(), 0);
832 Ok(())
833 }
834}