@@ -110,6 +110,43 @@ impl<O: IntegerPType, S: IntegerPType> ListViewBuilder<O, S> {
110110 }
111111 }
112112
113+ /// Appends an array as a single non-null list entry to the builder.
114+ ///
115+ /// The input `array` must have the same dtype as the element dtype of this list builder.
116+ ///
117+ /// Note that the list entry will be non-null but the elements themselves are allowed to be null
118+ /// (only if the elements [`DType`] is nullable, of course).
119+ pub fn append_array_as_list ( & mut self , array : & dyn Array ) -> VortexResult < ( ) > {
120+ vortex_ensure ! (
121+ array. dtype( ) == self . element_dtype( ) ,
122+ "Array dtype {:?} does not match list element dtype {:?}" ,
123+ array. dtype( ) ,
124+ self . element_dtype( )
125+ ) ;
126+
127+ let curr_offset = self . elements_builder . len ( ) ;
128+ let num_elements = array. len ( ) ;
129+
130+ // We must assert this even in release mode to ensure that the safety comment in
131+ // `finish_into_listview` is correct.
132+ assert ! (
133+ ( ( curr_offset + num_elements) as u64 ) < O :: max_value_as_u64( ) ,
134+ "appending this list would cause an offset overflow"
135+ ) ;
136+
137+ self . elements_builder . extend_from_array ( array) ;
138+ self . nulls . append_non_null ( ) ;
139+
140+ self . offsets_builder . append_value (
141+ O :: from_usize ( curr_offset) . vortex_expect ( "Failed to convert from usize to `O`" ) ,
142+ ) ;
143+ self . sizes_builder . append_value (
144+ S :: from_usize ( num_elements) . vortex_expect ( "Failed to convert from usize to `S`" ) ,
145+ ) ;
146+
147+ Ok ( ( ) )
148+ }
149+
113150 /// Append a list of values to the builder.
114151 ///
115152 /// This method extends the value builder with the provided values and records
@@ -633,4 +670,60 @@ mod tests {
633670 . contains( "null value to non-nullable" )
634671 ) ;
635672 }
673+
674+ #[ test]
675+ fn test_append_array_as_list ( ) {
676+ use vortex_buffer:: buffer;
677+
678+ use crate :: ToCanonical ;
679+
680+ let dtype: Arc < DType > = Arc :: new ( I32 . into ( ) ) ;
681+ let mut builder =
682+ ListViewBuilder :: < u32 , u32 > :: with_capacity ( dtype. clone ( ) , NonNullable , 20 , 10 ) ;
683+
684+ // Append a primitive array as a single list entry.
685+ let arr1 = buffer ! [ 1i32 , 2 , 3 ] . into_array ( ) ;
686+ builder. append_array_as_list ( & arr1) . unwrap ( ) ;
687+
688+ // Interleave with a list scalar.
689+ builder
690+ . append_value (
691+ Scalar :: list ( dtype. clone ( ) , vec ! [ 10i32 . into( ) , 11i32 . into( ) ] , NonNullable )
692+ . as_list ( ) ,
693+ )
694+ . unwrap ( ) ;
695+
696+ // Append another primitive array as a single list entry.
697+ let arr2 = buffer ! [ 4i32 , 5 ] . into_array ( ) ;
698+ builder. append_array_as_list ( & arr2) . unwrap ( ) ;
699+
700+ // Append an empty array as a single list entry (empty list).
701+ let arr3 = buffer ! [ 0i32 ; 0 ] . into_array ( ) ;
702+ builder. append_array_as_list ( & arr3) . unwrap ( ) ;
703+
704+ // Interleave with another list scalar.
705+ builder
706+ . append_value ( Scalar :: list_empty ( dtype. clone ( ) , NonNullable ) . as_list ( ) )
707+ . unwrap ( ) ;
708+
709+ let listview = builder. finish_into_listview ( ) ;
710+ assert_eq ! ( listview. len( ) , 5 ) ;
711+
712+ // Verify elements array: [1, 2, 3, 10, 11, 4, 5].
713+ let elements = listview. elements ( ) . to_primitive ( ) ;
714+ assert_eq ! ( elements. as_slice:: <i32 >( ) , & [ 1 , 2 , 3 , 10 , 11 , 4 , 5 ] ) ;
715+
716+ // Verify offsets array.
717+ let offsets = listview. offsets ( ) . to_primitive ( ) ;
718+ assert_eq ! ( offsets. as_slice:: <u32 >( ) , & [ 0 , 3 , 5 , 7 , 7 ] ) ;
719+
720+ // Verify sizes array.
721+ let sizes = listview. sizes ( ) . to_primitive ( ) ;
722+ assert_eq ! ( sizes. as_slice:: <u32 >( ) , & [ 3 , 2 , 2 , 0 , 0 ] ) ;
723+
724+ // Test dtype mismatch error.
725+ let mut builder = ListViewBuilder :: < u32 , u32 > :: with_capacity ( dtype, NonNullable , 20 , 10 ) ;
726+ let wrong_dtype_arr = buffer ! [ 1i64 , 2 , 3 ] . into_array ( ) ;
727+ assert ! ( builder. append_array_as_list( & wrong_dtype_arr) . is_err( ) ) ;
728+ }
636729}
0 commit comments