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