1use vortex_error::VortexExpect;
5use vortex_error::VortexResult;
6
7use crate::ArrayRef;
8use crate::Canonical;
9use crate::ExecutionCtx;
10use crate::IntoArray;
11use crate::arrays::ExtensionArray;
12use crate::arrays::FixedSizeListArray;
13use crate::arrays::ListArray;
14use crate::arrays::ListViewArray;
15use crate::arrays::PrimitiveArray;
16use crate::arrays::StructArray;
17use crate::arrays::extension::ExtensionArrayExt;
18use crate::arrays::fixed_size_list::FixedSizeListArrayExt;
19use crate::arrays::list::ListArrayExt;
20use crate::arrays::listview::ListViewArrayExt;
21use crate::arrays::listview::ListViewRebuildMode;
22use crate::arrays::struct_::StructArrayExt;
23use crate::builders::PrimitiveBuilder;
24use crate::dtype::IntegerPType;
25use crate::dtype::Nullability;
26use crate::match_each_integer_ptype;
27
28pub fn list_view_from_list(list: ListArray, ctx: &mut ExecutionCtx) -> VortexResult<ListViewArray> {
33 if list.is_empty() {
36 return Ok(Canonical::empty(list.dtype()).into_listview());
37 }
38
39 let list = list.reset_offsets(false, ctx)?;
43 let list_offsets = list.offsets().clone();
44
45 let sizes = match_each_integer_ptype!(list_offsets.dtype().as_ptype(), |O| {
48 build_sizes_from_offsets::<O>(&list, ctx)?
49 });
50
51 debug_assert_eq!(list_offsets.len(), list.len() + 1);
53 let adjusted_offsets = list_offsets.slice(0..list.len())?;
54
55 Ok(unsafe {
59 ListViewArray::new_unchecked(
60 list.elements().clone(),
61 adjusted_offsets,
62 sizes,
63 list.validity()?,
64 )
65 .with_zero_copy_to_list(true)
66 })
67}
68
69fn build_sizes_from_offsets<O: IntegerPType>(
71 list: &ListArray,
72 ctx: &mut ExecutionCtx,
73) -> VortexResult<ArrayRef> {
74 let len = list.len();
75 let mut sizes_builder = PrimitiveBuilder::<O>::with_capacity(Nullability::NonNullable, len);
76
77 let mut sizes_range = sizes_builder.uninit_range(len);
79
80 let offsets = list.offsets().clone().execute::<PrimitiveArray>(ctx)?;
81 let offsets_slice = offsets.as_slice::<O>();
82 debug_assert_eq!(len + 1, offsets_slice.len());
83 debug_assert!(offsets_slice.is_sorted());
84
85 for i in 0..len {
87 let size = offsets_slice[i + 1] - offsets_slice[i];
88 sizes_range.set_value(i, size);
89 }
90
91 unsafe {
93 sizes_range.finish();
94 }
95
96 Ok(sizes_builder.finish_into_primitive().into_array())
97}
98
99pub fn list_from_list_view(
109 list_view: ListViewArray,
110 ctx: &mut ExecutionCtx,
111) -> VortexResult<ListArray> {
112 let zctl_array = list_view.rebuild(ListViewRebuildMode::MakeExact, ctx)?;
114 debug_assert!(zctl_array.is_zero_copy_to_list());
115
116 let list_offsets = match_each_integer_ptype!(zctl_array.offsets().dtype().as_ptype(), |O| {
117 unsafe { build_list_offsets_from_list_view::<O>(&zctl_array, ctx) }
120 });
121
122 Ok(unsafe {
126 ListArray::new_unchecked(
127 zctl_array.elements().clone(),
128 list_offsets,
129 zctl_array.validity()?,
130 )
131 })
132}
133
134unsafe fn build_list_offsets_from_list_view<O: IntegerPType>(
144 list_view: &ListViewArray,
145 ctx: &mut ExecutionCtx,
146) -> ArrayRef {
147 let len = list_view.len();
148 let mut offsets_builder =
149 PrimitiveBuilder::<O>::with_capacity(Nullability::NonNullable, len + 1);
150
151 let mut offsets_range = offsets_builder.uninit_range(len + 1);
153
154 let offsets = list_view
155 .offsets()
156 .clone()
157 .execute::<PrimitiveArray>(ctx)
158 .vortex_expect("list view offsets must be primitive after rebuild");
159 let offsets_slice = offsets.as_slice::<O>();
160 debug_assert!(offsets_slice.is_sorted());
161
162 offsets_range.copy_from_slice(0, offsets_slice);
164
165 let final_offset = if len != 0 {
167 let last_offset = offsets_slice[len - 1];
168
169 let last_size = list_view.size_at(len - 1);
170 let last_size =
171 O::from_usize(last_size).vortex_expect("size somehow did not fit into offsets");
172
173 last_offset + last_size
174 } else {
175 O::zero()
176 };
177
178 offsets_range.set_value(len, final_offset);
179
180 unsafe {
182 offsets_range.finish();
183 }
184
185 offsets_builder.finish_into_primitive().into_array()
186}
187
188pub fn recursive_list_from_list_view(
192 array: ArrayRef,
193 ctx: &mut ExecutionCtx,
194) -> VortexResult<ArrayRef> {
195 if !array.dtype().is_nested() {
196 return Ok(array);
197 }
198
199 let canonical = array.execute::<Canonical>(ctx)?;
200
201 Ok(match canonical {
202 Canonical::List(listview) => {
203 let converted_elements =
204 recursive_list_from_list_view(listview.elements().clone(), ctx)?;
205 debug_assert_eq!(converted_elements.len(), listview.elements().len());
206
207 let listview_with_converted_elements =
209 if !ArrayRef::ptr_eq(&converted_elements, listview.elements()) {
210 unsafe {
213 ListViewArray::new_unchecked(
214 converted_elements,
215 listview.offsets().clone(),
216 listview.sizes().clone(),
217 listview.validity()?,
218 )
219 .with_zero_copy_to_list(listview.is_zero_copy_to_list())
220 }
221 } else {
222 listview
223 };
224
225 let list_array = list_from_list_view(listview_with_converted_elements, ctx)?;
227 list_array.into_array()
228 }
229 Canonical::FixedSizeList(fixed_size_list) => {
230 let converted_elements =
231 recursive_list_from_list_view(fixed_size_list.elements().clone(), ctx)?;
232
233 if !ArrayRef::ptr_eq(&converted_elements, fixed_size_list.elements()) {
235 FixedSizeListArray::try_new(
236 converted_elements,
237 fixed_size_list.list_size(),
238 fixed_size_list.validity()?,
239 fixed_size_list.len(),
240 )
241 .vortex_expect(
242 "FixedSizeListArray reconstruction should not fail with valid components",
243 )
244 .into_array()
245 } else {
246 fixed_size_list.into_array()
247 }
248 }
249 Canonical::Struct(struct_array) => {
250 let fields = struct_array.unmasked_fields();
251 let mut converted_fields = Vec::with_capacity(fields.len());
252 let mut any_changed = false;
253
254 for field in fields.iter() {
255 let converted_field = recursive_list_from_list_view(field.clone(), ctx)?;
256 any_changed |= !ArrayRef::ptr_eq(&converted_field, field);
258 converted_fields.push(converted_field);
259 }
260
261 if any_changed {
262 StructArray::try_new(
263 struct_array.names().clone(),
264 converted_fields,
265 struct_array.len(),
266 struct_array.validity()?,
267 )
268 .vortex_expect("StructArray reconstruction should not fail with valid components")
269 .into_array()
270 } else {
271 struct_array.into_array()
272 }
273 }
274 Canonical::Extension(ext_array) => {
275 let converted_storage =
276 recursive_list_from_list_view(ext_array.storage_array().clone(), ctx)?;
277
278 if !ArrayRef::ptr_eq(&converted_storage, ext_array.storage_array()) {
280 ExtensionArray::new(ext_array.ext_dtype().clone(), converted_storage).into_array()
281 } else {
282 ext_array.into_array()
283 }
284 }
285 _ => unreachable!(),
286 })
287}
288
289#[cfg(test)]
290mod tests {
291
292 use vortex_buffer::buffer;
293 use vortex_error::VortexExpect;
294 use vortex_error::VortexResult;
295
296 use super::super::tests::common::SESSION;
297 use super::super::tests::common::create_basic_listview;
298 use super::super::tests::common::create_empty_lists_listview;
299 use super::super::tests::common::create_nullable_listview;
300 use super::super::tests::common::create_overlapping_listview;
301 use super::recursive_list_from_list_view;
302 use crate::ArrayEq;
303 use crate::ArrayRef;
304 use crate::EqMode;
305 use crate::IntoArray;
306 use crate::VortexSessionExecute;
307 use crate::arrays::BoolArray;
308 use crate::arrays::FixedSizeListArray;
309 use crate::arrays::ListArray;
310 use crate::arrays::ListViewArray;
311 use crate::arrays::PrimitiveArray;
312 use crate::arrays::StructArray;
313 use crate::arrays::VarBinViewArray;
314 use crate::arrays::list::ListArrayExt;
315 use crate::arrays::listview::ListViewArrayExt;
316 use crate::arrays::listview::list_from_list_view;
317 use crate::arrays::listview::list_view_from_list;
318 use crate::assert_arrays_eq;
319 use crate::dtype::FieldNames;
320 use crate::validity::Validity;
321
322 #[test]
323 fn test_list_to_listview_basic() -> VortexResult<()> {
324 let elements = buffer![0i32, 1, 2, 3, 4, 5, 6, 7, 8, 9].into_array();
326 let offsets = buffer![0u32, 3, 5, 7, 10].into_array();
327 let list_array = ListArray::try_new(elements.clone(), offsets, Validity::NonNullable)?;
328
329 let mut ctx = SESSION.create_execution_ctx();
330 let list_view = list_view_from_list(list_array.clone(), &mut ctx)?;
331
332 assert_eq!(list_view.len(), 4);
334 assert_arrays_eq!(elements, list_view.elements().clone(), &mut ctx);
335
336 let expected_offsets = buffer![0u32, 3, 5, 7].into_array();
338 assert_arrays_eq!(expected_offsets, list_view.offsets().clone(), &mut ctx);
339
340 let expected_sizes = buffer![3u32, 2, 2, 3].into_array();
342 assert_arrays_eq!(expected_sizes, list_view.sizes().clone(), &mut ctx);
343
344 assert_arrays_eq!(list_array, list_view, &mut ctx);
346 Ok(())
347 }
348
349 #[test]
350 fn test_listview_to_list_zero_copy() -> VortexResult<()> {
351 let mut ctx = SESSION.create_execution_ctx();
352 let list_view = create_basic_listview();
353 let list_array =
354 list_from_list_view(list_view.clone(), &mut SESSION.create_execution_ctx())?;
355
356 assert_arrays_eq!(
358 list_view.elements().clone(),
359 list_array.elements().clone(),
360 &mut ctx
361 );
362
363 let list_array_offsets_without_last = list_array.offsets().slice(0..list_view.len())?;
366 assert_arrays_eq!(
367 list_view.offsets().clone(),
368 list_array_offsets_without_last,
369 &mut ctx
370 );
371
372 assert_arrays_eq!(list_view, list_array, &mut ctx);
374 Ok(())
375 }
376
377 #[test]
378 fn test_empty_array_conversions() -> VortexResult<()> {
379 let empty_elements = PrimitiveArray::from_iter::<[i32; 0]>([]).into_array();
381 let empty_offsets = buffer![0u32].into_array();
382 let empty_list = ListArray::try_new(empty_elements, empty_offsets, Validity::NonNullable)?;
383
384 let mut ctx = SESSION.create_execution_ctx();
387 let empty_list_view = list_view_from_list(empty_list.clone(), &mut ctx)?;
388 assert_eq!(empty_list_view.len(), 0);
389
390 let converted_back = list_from_list_view(empty_list_view, &mut ctx)?;
392 assert_eq!(converted_back.len(), 0);
393 assert_eq!(empty_list.len(), converted_back.len());
396 Ok(())
397 }
398
399 #[test]
400 fn test_nullable_conversions() -> VortexResult<()> {
401 let elements = buffer![10i32, 20, 30, 40, 50].into_array();
403 let offsets = buffer![0u32, 2, 4, 5].into_array();
404 let validity = Validity::Array(BoolArray::from_iter(vec![true, false, true]).into_array());
405 let nullable_list = ListArray::try_new(elements, offsets, validity.clone())?;
406
407 let mut ctx = SESSION.create_execution_ctx();
408 let nullable_list_view = list_view_from_list(nullable_list.clone(), &mut ctx)?;
409
410 assert!(
412 nullable_list_view
413 .validity()
414 .vortex_expect("listview validity should be derivable")
415 .array_eq(&validity, EqMode::Ptr)
416 );
417 assert_eq!(nullable_list_view.len(), 3);
418
419 let converted_back = list_from_list_view(nullable_list_view, &mut ctx)?;
421 assert_arrays_eq!(nullable_list, converted_back, &mut ctx);
422 Ok(())
423 }
424
425 #[test]
426 fn test_non_zero_copy_listview_to_list() -> VortexResult<()> {
427 let mut ctx = SESSION.create_execution_ctx();
428 let list_view = create_overlapping_listview();
430 let list_array =
431 list_from_list_view(list_view.clone(), &mut SESSION.create_execution_ctx())?;
432
433 for i in 0..list_array.len() {
435 let start = list_array.offset_at(i)?;
436 let end = list_array.offset_at(i + 1)?;
437 assert!(end >= start, "Offsets should be monotonic after conversion");
438 }
439
440 assert_arrays_eq!(list_view, list_array, &mut ctx);
442 Ok(())
443 }
444
445 #[test]
446 fn test_empty_sublists() -> VortexResult<()> {
447 let mut ctx = SESSION.create_execution_ctx();
448 let empty_lists_view = create_empty_lists_listview();
449
450 let list_array = list_from_list_view(empty_lists_view.clone(), &mut ctx)?;
452 assert_eq!(list_array.len(), 4);
453
454 for i in 0..list_array.len() {
456 assert_eq!(list_array.list_elements_at(i)?.len(), 0);
457 }
458
459 let converted_back = list_view_from_list(list_array, &mut ctx)?;
461 assert_arrays_eq!(empty_lists_view, converted_back, &mut ctx);
462 Ok(())
463 }
464
465 #[test]
466 fn test_different_offset_types() -> VortexResult<()> {
467 let elements = buffer![1i32, 2, 3, 4, 5].into_array();
469 let i32_offsets = buffer![0i32, 2, 5].into_array();
470 let list_i32 =
471 ListArray::try_new(elements.clone(), i32_offsets.clone(), Validity::NonNullable)?;
472
473 let mut ctx = SESSION.create_execution_ctx();
474 let list_view_i32 = list_view_from_list(list_i32.clone(), &mut ctx)?;
475 assert_eq!(list_view_i32.offsets().dtype(), i32_offsets.dtype());
476 assert_eq!(list_view_i32.sizes().dtype(), i32_offsets.dtype());
477
478 let i64_offsets = buffer![0i64, 2, 5].into_array();
480 let list_i64 = ListArray::try_new(elements, i64_offsets.clone(), Validity::NonNullable)?;
481
482 let list_view_i64 = list_view_from_list(list_i64.clone(), &mut ctx)?;
483 assert_eq!(list_view_i64.offsets().dtype(), i64_offsets.dtype());
484 assert_eq!(list_view_i64.sizes().dtype(), i64_offsets.dtype());
485
486 assert_arrays_eq!(list_i32, list_view_i32, &mut ctx);
488 assert_arrays_eq!(list_i64, list_view_i64, &mut ctx);
489 Ok(())
490 }
491
492 #[test]
493 fn test_round_trip_conversions() -> VortexResult<()> {
494 let mut ctx = SESSION.create_execution_ctx();
495
496 let original = create_basic_listview();
498 let to_list = list_from_list_view(original.clone(), &mut ctx)?;
499 let back_to_view = list_view_from_list(to_list, &mut ctx)?;
500 assert_arrays_eq!(original, back_to_view, &mut ctx);
501
502 let nullable = create_nullable_listview();
504 let nullable_to_list = list_from_list_view(nullable.clone(), &mut ctx)?;
505 let nullable_back = list_view_from_list(nullable_to_list, &mut ctx)?;
506 assert_arrays_eq!(nullable, nullable_back, &mut ctx);
507
508 let overlapping = create_overlapping_listview();
510
511 let overlapping_to_list = list_from_list_view(overlapping.clone(), &mut ctx)?;
512 let overlapping_back = list_view_from_list(overlapping_to_list, &mut ctx)?;
513 assert_arrays_eq!(overlapping, overlapping_back, &mut ctx);
514 Ok(())
515 }
516
517 #[test]
518 fn test_single_element_lists() -> VortexResult<()> {
519 let elements = buffer![100i32, 200, 300].into_array();
521 let offsets = buffer![0u32, 1, 2, 3].into_array();
522 let single_elem_list = ListArray::try_new(elements, offsets, Validity::NonNullable)?;
523
524 let mut ctx = SESSION.create_execution_ctx();
525 let list_view = list_view_from_list(single_elem_list.clone(), &mut ctx)?;
526 assert_eq!(list_view.len(), 3);
527
528 let expected_sizes = buffer![1u32, 1, 1].into_array();
530 assert_arrays_eq!(expected_sizes, list_view.sizes().clone(), &mut ctx);
531
532 let converted_back = list_from_list_view(list_view, &mut ctx)?;
534 assert_arrays_eq!(single_elem_list, converted_back, &mut ctx);
535 Ok(())
536 }
537
538 #[test]
539 fn test_mixed_empty_and_non_empty_lists() -> VortexResult<()> {
540 let elements = buffer![1i32, 2, 3, 4, 5, 6].into_array();
542 let offsets = buffer![0u32, 2, 2, 3, 3, 6].into_array();
543 let mixed_list = ListArray::try_new(elements, offsets, Validity::NonNullable)?;
544
545 let mut ctx = SESSION.create_execution_ctx();
546 let list_view = list_view_from_list(mixed_list.clone(), &mut ctx)?;
547 assert_eq!(list_view.len(), 5);
548
549 let expected_sizes = buffer![2u32, 0, 1, 0, 3].into_array();
551 assert_arrays_eq!(expected_sizes, list_view.sizes().clone(), &mut ctx);
552
553 let converted_back = list_from_list_view(list_view, &mut ctx)?;
555 assert_arrays_eq!(mixed_list, converted_back, &mut ctx);
556 Ok(())
557 }
558
559 #[test]
560 fn test_recursive_simple_listview() -> VortexResult<()> {
561 let mut ctx = SESSION.create_execution_ctx();
562 let list_view = create_basic_listview();
563 let result = recursive_list_from_list_view(
564 list_view.clone().into_array(),
565 &mut SESSION.create_execution_ctx(),
566 )?;
567
568 assert_eq!(result.len(), list_view.len());
569 assert_arrays_eq!(list_view.into_array(), result, &mut ctx);
570 Ok(())
571 }
572
573 #[test]
574 fn test_recursive_nested_listview() -> VortexResult<()> {
575 let mut ctx = SESSION.create_execution_ctx();
576 let inner_elements = buffer![1i32, 2, 3].into_array();
577 let inner_offsets = buffer![0u32, 2].into_array();
578 let inner_sizes = buffer![2u32, 1].into_array();
579 let inner_listview = unsafe {
580 ListViewArray::new_unchecked(
581 inner_elements,
582 inner_offsets,
583 inner_sizes,
584 Validity::NonNullable,
585 )
586 .with_zero_copy_to_list(true)
587 };
588
589 let outer_offsets = buffer![0u32, 1].into_array();
590 let outer_sizes = buffer![1u32, 1].into_array();
591 let outer_listview = unsafe {
592 ListViewArray::new_unchecked(
593 inner_listview.into_array(),
594 outer_offsets,
595 outer_sizes,
596 Validity::NonNullable,
597 )
598 .with_zero_copy_to_list(true)
599 };
600
601 let result = recursive_list_from_list_view(
602 outer_listview.clone().into_array(),
603 &mut SESSION.create_execution_ctx(),
604 )?;
605
606 assert_eq!(result.len(), 2);
607 assert_arrays_eq!(outer_listview.into_array(), result, &mut ctx);
608 Ok(())
609 }
610
611 #[test]
612 fn test_recursive_struct_with_listview_fields() -> VortexResult<()> {
613 let mut ctx = SESSION.create_execution_ctx();
614 let listview_field = create_basic_listview().into_array();
615 let primitive_field = buffer![10i32, 20, 30, 40].into_array();
616
617 let struct_array = StructArray::try_new(
618 FieldNames::from(["lists", "values"]),
619 vec![listview_field, primitive_field],
620 4,
621 Validity::NonNullable,
622 )?;
623
624 let result = recursive_list_from_list_view(
625 struct_array.clone().into_array(),
626 &mut SESSION.create_execution_ctx(),
627 )?;
628
629 assert_eq!(result.len(), 4);
630 assert_arrays_eq!(struct_array.into_array(), result, &mut ctx);
631 Ok(())
632 }
633
634 #[test]
635 fn test_recursive_fixed_size_list_with_listview_elements() -> VortexResult<()> {
636 let mut ctx = SESSION.create_execution_ctx();
637 let lv1_elements = buffer![1i32, 2].into_array();
638 let lv1_offsets = buffer![0u32].into_array();
639 let lv1_sizes = buffer![2u32].into_array();
640 let lv1 = unsafe {
641 ListViewArray::new_unchecked(
642 lv1_elements,
643 lv1_offsets,
644 lv1_sizes,
645 Validity::NonNullable,
646 )
647 .with_zero_copy_to_list(true)
648 };
649
650 let lv2_elements = buffer![3i32, 4].into_array();
651 let lv2_offsets = buffer![0u32].into_array();
652 let lv2_sizes = buffer![2u32].into_array();
653 let lv2 = unsafe {
654 ListViewArray::new_unchecked(
655 lv2_elements,
656 lv2_offsets,
657 lv2_sizes,
658 Validity::NonNullable,
659 )
660 .with_zero_copy_to_list(true)
661 };
662
663 let dtype = lv1.dtype().clone();
664 let chunked_listviews =
665 crate::arrays::ChunkedArray::try_new(vec![lv1.into_array(), lv2.into_array()], dtype)?;
666
667 let fixed_list =
668 FixedSizeListArray::new(chunked_listviews.into_array(), 1, Validity::NonNullable, 2);
669
670 let result = recursive_list_from_list_view(
671 fixed_list.clone().into_array(),
672 &mut SESSION.create_execution_ctx(),
673 )?;
674
675 assert_eq!(result.len(), 2);
676 assert_arrays_eq!(fixed_list.into_array(), result, &mut ctx);
677 Ok(())
678 }
679
680 #[test]
681 fn test_recursive_deep_nesting() -> VortexResult<()> {
682 let mut ctx = SESSION.create_execution_ctx();
683 let innermost_elements = buffer![1i32, 2, 3].into_array();
684 let innermost_offsets = buffer![0u32, 2].into_array();
685 let innermost_sizes = buffer![2u32, 1].into_array();
686 let innermost_listview = unsafe {
687 ListViewArray::new_unchecked(
688 innermost_elements,
689 innermost_offsets,
690 innermost_sizes,
691 Validity::NonNullable,
692 )
693 .with_zero_copy_to_list(true)
694 };
695
696 let struct_array = StructArray::try_new(
697 FieldNames::from(["inner_lists"]),
698 vec![innermost_listview.into_array()],
699 2,
700 Validity::NonNullable,
701 )?;
702
703 let outer_offsets = buffer![0u32, 1].into_array();
704 let outer_sizes = buffer![1u32, 1].into_array();
705 let outer_listview = unsafe {
706 ListViewArray::new_unchecked(
707 struct_array.into_array(),
708 outer_offsets,
709 outer_sizes,
710 Validity::NonNullable,
711 )
712 .with_zero_copy_to_list(true)
713 };
714
715 let result = recursive_list_from_list_view(
716 outer_listview.clone().into_array(),
717 &mut SESSION.create_execution_ctx(),
718 )?;
719
720 assert_eq!(result.len(), 2);
721 assert_arrays_eq!(outer_listview.into_array(), result, &mut ctx);
722 Ok(())
723 }
724
725 #[test]
726 fn test_recursive_primitive_unchanged() -> VortexResult<()> {
727 let prim = buffer![1i32, 2, 3].into_array();
728 let prim_clone = prim.clone();
729 let result = recursive_list_from_list_view(prim, &mut SESSION.create_execution_ctx())?;
730
731 assert!(ArrayRef::ptr_eq(&result, &prim_clone));
732 Ok(())
733 }
734
735 #[test]
736 fn test_recursive_mixed_listview_and_list() -> VortexResult<()> {
737 let mut ctx = SESSION.create_execution_ctx();
738 let listview = create_basic_listview();
739 let list = list_from_list_view(listview.clone(), &mut ctx)?;
740
741 let struct_array = StructArray::try_new(
742 FieldNames::from(["listview_field", "list_field"]),
743 vec![listview.into_array(), list.into_array()],
744 4,
745 Validity::NonNullable,
746 )?;
747
748 let result = recursive_list_from_list_view(struct_array.clone().into_array(), &mut ctx)?;
749
750 assert_eq!(result.len(), 4);
751 assert_arrays_eq!(struct_array.into_array(), result, &mut ctx);
752 Ok(())
753 }
754
755 #[test]
761 fn test_empty_listview_to_list_without_zctl_flag() -> VortexResult<()> {
762 let elements = VarBinViewArray::from_iter_str(Vec::<&str>::new()).into_array();
763 let offsets = PrimitiveArray::from_iter(Vec::<i16>::new()).into_array();
764 let sizes = PrimitiveArray::from_iter(Vec::<i16>::new()).into_array();
765 let list_view = ListViewArray::try_new(elements, offsets, sizes, Validity::AllValid)?;
766
767 assert!(!list_view.is_zero_copy_to_list());
769
770 let list_array = list_from_list_view(list_view, &mut SESSION.create_execution_ctx())?;
771 assert_eq!(list_array.len(), 0);
772 Ok(())
773 }
774}