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