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::FixedSizeListArray;
317 use crate::arrays::ListArray;
318 use crate::arrays::ListViewArray;
319 use crate::arrays::PrimitiveArray;
320 use crate::arrays::StructArray;
321 use crate::arrays::VarBinViewArray;
322 use crate::arrays::list::ListArrayExt;
323 use crate::arrays::list::ListArraySlotsExt;
324 use crate::arrays::listview::ListViewArraySlotsExt;
325 use crate::arrays::listview::list_from_list_view;
326 use crate::arrays::listview::list_view_from_list;
327 use crate::assert_arrays_eq;
328 use crate::dtype::FieldNames;
329 use crate::validity::Validity;
330
331 #[test]
332 fn test_list_to_listview_basic() -> VortexResult<()> {
333 let elements = buffer![0i32, 1, 2, 3, 4, 5, 6, 7, 8, 9].into_array();
335 let offsets = buffer![0u32, 3, 5, 7, 10].into_array();
336 let list_array = ListArray::try_new(elements.clone(), offsets, Validity::NonNullable)?;
337
338 let mut ctx = SESSION.create_execution_ctx();
339 let list_view = list_view_from_list(list_array.clone(), &mut ctx)?;
340
341 assert_eq!(list_view.len(), 4);
343 assert_arrays_eq!(elements, list_view.elements().clone(), &mut ctx);
344
345 let expected_offsets = buffer![0u32, 3, 5, 7].into_array();
347 assert_arrays_eq!(expected_offsets, list_view.offsets().clone(), &mut ctx);
348
349 let expected_sizes = buffer![3u32, 2, 2, 3].into_array();
351 assert_arrays_eq!(expected_sizes, list_view.sizes().clone(), &mut ctx);
352
353 assert_arrays_eq!(list_array, list_view, &mut ctx);
355 Ok(())
356 }
357
358 #[test]
359 fn test_list_to_listview_resets_nonzero_offsets() -> VortexResult<()> {
360 let elements = buffer![0i32, 1, 2, 3, 4].into_array();
361 let offsets = buffer![2u16, 4, 5].into_array();
362 let list = ListArray::try_new(elements, offsets, Validity::NonNullable)?;
363
364 let mut ctx = SESSION.create_execution_ctx();
365 let list_view = list_view_from_list(list.clone(), &mut ctx)?;
366
367 assert_arrays_eq!(
368 buffer![0u16, 2].into_array(),
369 list_view.offsets().clone(),
370 &mut ctx
371 );
372 assert_arrays_eq!(list, list_view, &mut ctx);
373 Ok(())
374 }
375
376 #[test]
377 fn test_listview_to_list_zero_copy() -> VortexResult<()> {
378 let mut ctx = SESSION.create_execution_ctx();
379 let list_view = create_basic_listview();
380 let list_array =
381 list_from_list_view(list_view.clone(), &mut SESSION.create_execution_ctx())?;
382
383 assert_arrays_eq!(
385 list_view.elements().clone(),
386 list_array.elements().clone(),
387 &mut ctx
388 );
389
390 let list_array_offsets_without_last = list_array.offsets().slice(0..list_view.len())?;
393 assert_arrays_eq!(
394 list_view.offsets().clone(),
395 list_array_offsets_without_last,
396 &mut ctx
397 );
398
399 assert_arrays_eq!(list_view, list_array, &mut ctx);
401 Ok(())
402 }
403
404 #[test]
405 fn test_empty_array_conversions() -> VortexResult<()> {
406 let empty_elements = PrimitiveArray::from_iter::<[i32; 0]>([]).into_array();
408 let empty_offsets = buffer![0u32].into_array();
409 let empty_list = ListArray::try_new(empty_elements, empty_offsets, Validity::NonNullable)?;
410
411 let mut ctx = SESSION.create_execution_ctx();
414 let empty_list_view = list_view_from_list(empty_list.clone(), &mut ctx)?;
415 assert_eq!(empty_list_view.len(), 0);
416
417 let converted_back = list_from_list_view(empty_list_view, &mut ctx)?;
419 assert_eq!(converted_back.len(), 0);
420 assert_eq!(empty_list.len(), converted_back.len());
423 Ok(())
424 }
425
426 #[test]
427 fn test_nullable_conversions() -> VortexResult<()> {
428 let elements = buffer![10i32, 20, 30, 40, 50].into_array();
430 let offsets = buffer![0u32, 2, 4, 5].into_array();
431 let validity = Validity::Array(BoolArray::from_iter(vec![true, false, true]).into_array());
432 let nullable_list = ListArray::try_new(elements, offsets, validity.clone())?;
433
434 let mut ctx = SESSION.create_execution_ctx();
435 let nullable_list_view = list_view_from_list(nullable_list.clone(), &mut ctx)?;
436
437 assert!(
439 nullable_list_view
440 .validity()
441 .vortex_expect("listview validity should be derivable")
442 .array_eq(&validity, EqMode::Ptr)
443 );
444 assert_eq!(nullable_list_view.len(), 3);
445
446 let converted_back = list_from_list_view(nullable_list_view, &mut ctx)?;
448 assert_arrays_eq!(nullable_list, converted_back, &mut ctx);
449 Ok(())
450 }
451
452 #[test]
453 fn test_non_zero_copy_listview_to_list() -> VortexResult<()> {
454 let mut ctx = SESSION.create_execution_ctx();
455 let list_view = create_overlapping_listview();
457 let list_array =
458 list_from_list_view(list_view.clone(), &mut SESSION.create_execution_ctx())?;
459
460 for i in 0..list_array.len() {
462 let start = list_array.offset_at(i)?;
463 let end = list_array.offset_at(i + 1)?;
464 assert!(end >= start, "Offsets should be monotonic after conversion");
465 }
466
467 assert_arrays_eq!(list_view, list_array, &mut ctx);
469 Ok(())
470 }
471
472 #[test]
473 fn test_empty_sublists() -> VortexResult<()> {
474 let mut ctx = SESSION.create_execution_ctx();
475 let empty_lists_view = create_empty_lists_listview();
476
477 let list_array = list_from_list_view(empty_lists_view.clone(), &mut ctx)?;
479 assert_eq!(list_array.len(), 4);
480
481 for i in 0..list_array.len() {
483 assert_eq!(list_array.list_elements_at(i)?.len(), 0);
484 }
485
486 let converted_back = list_view_from_list(list_array, &mut ctx)?;
488 assert_arrays_eq!(empty_lists_view, converted_back, &mut ctx);
489 Ok(())
490 }
491
492 #[test]
493 fn test_different_offset_types() -> VortexResult<()> {
494 let elements = buffer![1i32, 2, 3, 4, 5].into_array();
496 let i32_offsets = buffer![0i32, 2, 5].into_array();
497 let list_i32 =
498 ListArray::try_new(elements.clone(), i32_offsets.clone(), Validity::NonNullable)?;
499
500 let mut ctx = SESSION.create_execution_ctx();
501 let list_view_i32 = list_view_from_list(list_i32.clone(), &mut ctx)?;
502 assert_eq!(list_view_i32.offsets().dtype(), i32_offsets.dtype());
503 assert_eq!(list_view_i32.sizes().dtype(), i32_offsets.dtype());
504
505 let i64_offsets = buffer![0i64, 2, 5].into_array();
507 let list_i64 = ListArray::try_new(elements, i64_offsets.clone(), Validity::NonNullable)?;
508
509 let list_view_i64 = list_view_from_list(list_i64.clone(), &mut ctx)?;
510 assert_eq!(list_view_i64.offsets().dtype(), i64_offsets.dtype());
511 assert_eq!(list_view_i64.sizes().dtype(), i64_offsets.dtype());
512
513 assert_arrays_eq!(list_i32, list_view_i32, &mut ctx);
515 assert_arrays_eq!(list_i64, list_view_i64, &mut ctx);
516 Ok(())
517 }
518
519 #[test]
520 fn test_round_trip_conversions() -> VortexResult<()> {
521 let mut ctx = SESSION.create_execution_ctx();
522
523 let original = create_basic_listview();
525 let to_list = list_from_list_view(original.clone(), &mut ctx)?;
526 let back_to_view = list_view_from_list(to_list, &mut ctx)?;
527 assert_arrays_eq!(original, back_to_view, &mut ctx);
528
529 let nullable = create_nullable_listview();
531 let nullable_to_list = list_from_list_view(nullable.clone(), &mut ctx)?;
532 let nullable_back = list_view_from_list(nullable_to_list, &mut ctx)?;
533 assert_arrays_eq!(nullable, nullable_back, &mut ctx);
534
535 let overlapping = create_overlapping_listview();
537
538 let overlapping_to_list = list_from_list_view(overlapping.clone(), &mut ctx)?;
539 let overlapping_back = list_view_from_list(overlapping_to_list, &mut ctx)?;
540 assert_arrays_eq!(overlapping, overlapping_back, &mut ctx);
541 Ok(())
542 }
543
544 #[test]
545 fn test_single_element_lists() -> VortexResult<()> {
546 let elements = buffer![100i32, 200, 300].into_array();
548 let offsets = buffer![0u32, 1, 2, 3].into_array();
549 let single_elem_list = ListArray::try_new(elements, offsets, Validity::NonNullable)?;
550
551 let mut ctx = SESSION.create_execution_ctx();
552 let list_view = list_view_from_list(single_elem_list.clone(), &mut ctx)?;
553 assert_eq!(list_view.len(), 3);
554
555 let expected_sizes = buffer![1u32, 1, 1].into_array();
557 assert_arrays_eq!(expected_sizes, list_view.sizes().clone(), &mut ctx);
558
559 let converted_back = list_from_list_view(list_view, &mut ctx)?;
561 assert_arrays_eq!(single_elem_list, converted_back, &mut ctx);
562 Ok(())
563 }
564
565 #[test]
566 fn test_mixed_empty_and_non_empty_lists() -> VortexResult<()> {
567 let elements = buffer![1i32, 2, 3, 4, 5, 6].into_array();
569 let offsets = buffer![0u32, 2, 2, 3, 3, 6].into_array();
570 let mixed_list = ListArray::try_new(elements, offsets, Validity::NonNullable)?;
571
572 let mut ctx = SESSION.create_execution_ctx();
573 let list_view = list_view_from_list(mixed_list.clone(), &mut ctx)?;
574 assert_eq!(list_view.len(), 5);
575
576 let expected_sizes = buffer![2u32, 0, 1, 0, 3].into_array();
578 assert_arrays_eq!(expected_sizes, list_view.sizes().clone(), &mut ctx);
579
580 let converted_back = list_from_list_view(list_view, &mut ctx)?;
582 assert_arrays_eq!(mixed_list, converted_back, &mut ctx);
583 Ok(())
584 }
585
586 #[test]
587 fn test_recursive_simple_listview() -> VortexResult<()> {
588 let mut ctx = SESSION.create_execution_ctx();
589 let list_view = create_basic_listview();
590 let result = recursive_list_from_list_view(
591 list_view.clone().into_array(),
592 &mut SESSION.create_execution_ctx(),
593 )?;
594
595 assert_eq!(result.len(), list_view.len());
596 assert_arrays_eq!(list_view.into_array(), result, &mut ctx);
597 Ok(())
598 }
599
600 #[test]
601 fn test_recursive_nested_listview() -> VortexResult<()> {
602 let mut ctx = SESSION.create_execution_ctx();
603 let inner_elements = buffer![1i32, 2, 3].into_array();
604 let inner_offsets = buffer![0u32, 2].into_array();
605 let inner_sizes = buffer![2u32, 1].into_array();
606 let inner_listview = unsafe {
607 ListViewArray::new_unchecked(
608 inner_elements,
609 inner_offsets,
610 inner_sizes,
611 Validity::NonNullable,
612 )
613 .with_zero_copy_to_list(true)
614 };
615
616 let outer_offsets = buffer![0u32, 1].into_array();
617 let outer_sizes = buffer![1u32, 1].into_array();
618 let outer_listview = unsafe {
619 ListViewArray::new_unchecked(
620 inner_listview.into_array(),
621 outer_offsets,
622 outer_sizes,
623 Validity::NonNullable,
624 )
625 .with_zero_copy_to_list(true)
626 };
627
628 let result = recursive_list_from_list_view(
629 outer_listview.clone().into_array(),
630 &mut SESSION.create_execution_ctx(),
631 )?;
632
633 assert_eq!(result.len(), 2);
634 assert_arrays_eq!(outer_listview.into_array(), result, &mut ctx);
635 Ok(())
636 }
637
638 #[test]
639 fn test_recursive_struct_with_listview_fields() -> VortexResult<()> {
640 let mut ctx = SESSION.create_execution_ctx();
641 let listview_field = create_basic_listview().into_array();
642 let primitive_field = buffer![10i32, 20, 30, 40].into_array();
643
644 let struct_array = StructArray::try_new(
645 FieldNames::from(["lists", "values"]),
646 vec![listview_field, primitive_field],
647 4,
648 Validity::NonNullable,
649 )?;
650
651 let result = recursive_list_from_list_view(
652 struct_array.clone().into_array(),
653 &mut SESSION.create_execution_ctx(),
654 )?;
655
656 assert_eq!(result.len(), 4);
657 assert_arrays_eq!(struct_array.into_array(), result, &mut ctx);
658 Ok(())
659 }
660
661 #[test]
662 fn test_recursive_fixed_size_list_with_listview_elements() -> VortexResult<()> {
663 let mut ctx = SESSION.create_execution_ctx();
664 let lv1_elements = buffer![1i32, 2].into_array();
665 let lv1_offsets = buffer![0u32].into_array();
666 let lv1_sizes = buffer![2u32].into_array();
667 let lv1 = unsafe {
668 ListViewArray::new_unchecked(
669 lv1_elements,
670 lv1_offsets,
671 lv1_sizes,
672 Validity::NonNullable,
673 )
674 .with_zero_copy_to_list(true)
675 };
676
677 let lv2_elements = buffer![3i32, 4].into_array();
678 let lv2_offsets = buffer![0u32].into_array();
679 let lv2_sizes = buffer![2u32].into_array();
680 let lv2 = unsafe {
681 ListViewArray::new_unchecked(
682 lv2_elements,
683 lv2_offsets,
684 lv2_sizes,
685 Validity::NonNullable,
686 )
687 .with_zero_copy_to_list(true)
688 };
689
690 let dtype = lv1.dtype().clone();
691 let chunked_listviews =
692 crate::arrays::ChunkedArray::try_new(vec![lv1.into_array(), lv2.into_array()], dtype)?;
693
694 let fixed_list =
695 FixedSizeListArray::new(chunked_listviews.into_array(), 1, Validity::NonNullable, 2);
696
697 let result = recursive_list_from_list_view(
698 fixed_list.clone().into_array(),
699 &mut SESSION.create_execution_ctx(),
700 )?;
701
702 assert_eq!(result.len(), 2);
703 assert_arrays_eq!(fixed_list.into_array(), result, &mut ctx);
704 Ok(())
705 }
706
707 #[test]
708 fn test_recursive_deep_nesting() -> VortexResult<()> {
709 let mut ctx = SESSION.create_execution_ctx();
710 let innermost_elements = buffer![1i32, 2, 3].into_array();
711 let innermost_offsets = buffer![0u32, 2].into_array();
712 let innermost_sizes = buffer![2u32, 1].into_array();
713 let innermost_listview = unsafe {
714 ListViewArray::new_unchecked(
715 innermost_elements,
716 innermost_offsets,
717 innermost_sizes,
718 Validity::NonNullable,
719 )
720 .with_zero_copy_to_list(true)
721 };
722
723 let struct_array = StructArray::try_new(
724 FieldNames::from(["inner_lists"]),
725 vec![innermost_listview.into_array()],
726 2,
727 Validity::NonNullable,
728 )?;
729
730 let outer_offsets = buffer![0u32, 1].into_array();
731 let outer_sizes = buffer![1u32, 1].into_array();
732 let outer_listview = unsafe {
733 ListViewArray::new_unchecked(
734 struct_array.into_array(),
735 outer_offsets,
736 outer_sizes,
737 Validity::NonNullable,
738 )
739 .with_zero_copy_to_list(true)
740 };
741
742 let result = recursive_list_from_list_view(
743 outer_listview.clone().into_array(),
744 &mut SESSION.create_execution_ctx(),
745 )?;
746
747 assert_eq!(result.len(), 2);
748 assert_arrays_eq!(outer_listview.into_array(), result, &mut ctx);
749 Ok(())
750 }
751
752 #[test]
753 fn test_recursive_primitive_unchanged() -> VortexResult<()> {
754 let prim = buffer![1i32, 2, 3].into_array();
755 let prim_clone = prim.clone();
756 let result = recursive_list_from_list_view(prim, &mut SESSION.create_execution_ctx())?;
757
758 assert!(ArrayRef::ptr_eq(&result, &prim_clone));
759 Ok(())
760 }
761
762 #[test]
763 fn test_recursive_mixed_listview_and_list() -> VortexResult<()> {
764 let mut ctx = SESSION.create_execution_ctx();
765 let listview = create_basic_listview();
766 let list = list_from_list_view(listview.clone(), &mut ctx)?;
767
768 let struct_array = StructArray::try_new(
769 FieldNames::from(["listview_field", "list_field"]),
770 vec![listview.into_array(), list.into_array()],
771 4,
772 Validity::NonNullable,
773 )?;
774
775 let result = recursive_list_from_list_view(struct_array.clone().into_array(), &mut ctx)?;
776
777 assert_eq!(result.len(), 4);
778 assert_arrays_eq!(struct_array.into_array(), result, &mut ctx);
779 Ok(())
780 }
781
782 #[test]
788 fn test_empty_listview_to_list_without_zctl_flag() -> VortexResult<()> {
789 let elements = VarBinViewArray::from_iter_str(Vec::<&str>::new()).into_array();
790 let offsets = PrimitiveArray::from_iter(Vec::<i16>::new()).into_array();
791 let sizes = PrimitiveArray::from_iter(Vec::<i16>::new()).into_array();
792 let list_view = ListViewArray::try_new(elements, offsets, sizes, Validity::AllValid)?;
793
794 assert!(!list_view.is_zero_copy_to_list());
796
797 let list_array = list_from_list_view(list_view, &mut SESSION.create_execution_ctx())?;
798 assert_eq!(list_array.len(), 0);
799 Ok(())
800 }
801}