33
44//! Definition and implementation of [`StructVector`].
55
6+ use vortex_error:: { VortexExpect , VortexResult , vortex_ensure} ;
67use vortex_mask:: Mask ;
78
89use crate :: { StructVectorMut , Vector , VectorMutOps , VectorOps } ;
@@ -18,24 +19,113 @@ pub struct StructVector {
1819 /// The fields of the `StructVector`, each stored column-wise as a [`Vector`].
1920 pub ( super ) fields : Box < [ Vector ] > ,
2021
22+ /// The validity mask (where `true` represents an element is **not** null).
23+ pub ( super ) validity : Mask ,
24+
2125 /// The length of the vector (which is the same as all field vectors).
2226 ///
2327 /// This is stored here as a convenience, and also helps in the case that the `StructVector` has
2428 /// no fields.
2529 pub ( super ) len : usize ,
30+ }
2631
27- /// The capacity of the vector (which is the less than or equal to the capacity of all field
28- /// vectors).
32+ impl StructVector {
33+ /// Creates a new [`StructVector`] from the given fields and validity mask.
34+ ///
35+ /// # Panics
36+ ///
37+ /// Panics if:
2938 ///
30- /// This is stored here as a convenience for converting to/from a [`StructVectorMut`], and also
31- /// helps in the case that the `StructVector` has no fields.
32- pub ( super ) capacity : usize ,
39+ /// - Any field vector has a length that does not match the length of other fields.
40+ /// - The validity mask length does not match the field length.
41+ pub fn new ( fields : Box < [ Vector ] > , validity : Mask ) -> Self {
42+ Self :: try_new ( fields, validity) . vortex_expect (
43+ "`StructVector` fields must have matching length and validity constraints" ,
44+ )
45+ }
3346
34- /// The validity mask (where `true` represents an element is **not** null).
35- pub ( super ) validity : Mask ,
36- }
47+ /// Tries to create a new [`StructVector`] from the given fields and validity mask.
48+ ///
49+ /// # Errors
50+ ///
51+ /// Returns an error if:
52+ ///
53+ /// - Any field vector has a length that does not match the length of other fields.
54+ /// - The validity mask length does not match the field length.
55+ pub fn try_new ( fields : Box < [ Vector ] > , validity : Mask ) -> VortexResult < Self > {
56+ let len = if fields. is_empty ( ) {
57+ validity. len ( )
58+ } else {
59+ fields[ 0 ] . len ( )
60+ } ;
61+
62+ Self :: validate ( & fields, len, & validity) ?;
63+
64+ Ok ( Self {
65+ fields,
66+ validity,
67+ len,
68+ } )
69+ }
70+
71+ /// Creates a new [`StructVector`] from the given fields and validity mask without validation.
72+ ///
73+ /// # Safety
74+ ///
75+ /// The caller must ensure that:
76+ ///
77+ /// - All field vectors have the same length.
78+ /// - The validity mask has a length equal to the field length.
79+ pub unsafe fn new_unchecked ( fields : Box < [ Vector ] > , validity : Mask ) -> Self {
80+ let len = if fields. is_empty ( ) {
81+ validity. len ( )
82+ } else {
83+ fields[ 0 ] . len ( )
84+ } ;
85+
86+ debug_assert ! (
87+ Self :: validate( & fields, len, & validity) . is_ok( ) ,
88+ "`StructVector` fields must have matching length and validity constraints"
89+ ) ;
90+
91+ Self {
92+ fields,
93+ validity,
94+ len,
95+ }
96+ }
97+
98+ /// Validates the fields and validity mask for a [`StructVector`].
99+ ///
100+ /// # Errors
101+ ///
102+ /// Returns an error if:
103+ ///
104+ /// - Any field vector has a length that does not match the length of other fields.
105+ /// - The validity mask length does not match the field length.
106+ fn validate ( fields : & [ Vector ] , len : usize , validity : & Mask ) -> VortexResult < ( ) > {
107+ // Validate that the validity mask has the correct length.
108+ vortex_ensure ! (
109+ validity. len( ) == len,
110+ "Validity mask length ({}) does not match expected length ({})" ,
111+ validity. len( ) ,
112+ len
113+ ) ;
114+
115+ // Validate that all fields have the correct length.
116+ for ( i, field) in fields. iter ( ) . enumerate ( ) {
117+ vortex_ensure ! (
118+ field. len( ) == len,
119+ "Field {} has length {} but expected length {}" ,
120+ i,
121+ field. len( ) ,
122+ len
123+ ) ;
124+ }
125+
126+ Ok ( ( ) )
127+ }
37128
38- impl StructVector {
39129 /// Returns the fields of the `StructVector`, each stored column-wise as a [`Vector`].
40130 pub fn fields ( & self ) -> & [ Vector ] {
41131 self . fields . as_ref ( )
@@ -89,7 +179,6 @@ impl VectorOps for StructVector {
89179 return Err ( StructVector {
90180 fields : all_fields. into_boxed_slice ( ) ,
91181 len : self . len ,
92- capacity : self . capacity ,
93182 validity : validity. freeze ( ) ,
94183 } ) ;
95184 }
@@ -99,220 +188,7 @@ impl VectorOps for StructVector {
99188 Ok ( StructVectorMut {
100189 fields : mutable_fields,
101190 len : self . len ,
102- capacity : self . capacity ,
103191 validity,
104192 } )
105193 }
106194}
107-
108- #[ cfg( test) ]
109- mod tests {
110- use vortex_mask:: Mask ;
111-
112- use super :: * ;
113- use crate :: { BoolVectorMut , NullVector , PVectorMut , VectorMut } ;
114-
115- // TODO(connor): Make sure to test actual logic instead of just lengths and capacity.
116-
117- /// Helper function to create a `StructVector` with the given fields.
118- fn create_struct_vector ( fields : Vec < Vector > , len : usize , capacity : usize ) -> StructVector {
119- StructVector {
120- fields : fields. into_boxed_slice ( ) ,
121- len,
122- capacity,
123- validity : Mask :: AllTrue ( len) ,
124- }
125- }
126-
127- #[ test]
128- fn test_try_into_mut_success ( ) {
129- // Create a `StructVector` with 3 different field types (null, bool, primitive).
130- let null_field: Vector = NullVector :: new ( 5 ) . into ( ) ;
131- let bool_field: Vector = BoolVectorMut :: from_iter ( [ true , false , true , false , true ] )
132- . freeze ( )
133- . into ( ) ;
134- let prim_field: Vector = PVectorMut :: < i32 > :: from_iter ( [ 10 , 20 , 30 , 40 , 50 ] )
135- . freeze ( )
136- . into ( ) ;
137-
138- let struct_vec = create_struct_vector ( vec ! [ null_field, bool_field, prim_field] , 5 , 5 ) ;
139-
140- // Attempt to convert to mutable.
141- let result = struct_vec. try_into_mut ( ) ;
142-
143- // Should succeed since all fields have unique ownership.
144- assert ! ( result. is_ok( ) ) ;
145-
146- let mut_struct = result. unwrap ( ) ;
147-
148- // Verify the mutable struct has correct length and capacity.
149- assert_eq ! ( mut_struct. len( ) , 5 ) ;
150- assert_eq ! ( mut_struct. capacity( ) , 5 ) ;
151-
152- // Verify that we have 3 fields.
153- assert_eq ! ( mut_struct. fields. len( ) , 3 ) ;
154-
155- // Verify each field has the correct type and length.
156- assert ! ( matches!( mut_struct. fields[ 0 ] , VectorMut :: Null ( _) ) ) ;
157- assert_eq ! ( mut_struct. fields[ 0 ] . len( ) , 5 ) ;
158-
159- assert ! ( matches!( mut_struct. fields[ 1 ] , VectorMut :: Bool ( _) ) ) ;
160- assert_eq ! ( mut_struct. fields[ 1 ] . len( ) , 5 ) ;
161- assert ! ( mut_struct. fields[ 1 ] . capacity( ) >= 5 ) ;
162-
163- assert ! ( matches!( mut_struct. fields[ 2 ] , VectorMut :: Primitive ( _) ) ) ;
164- assert_eq ! ( mut_struct. fields[ 2 ] . len( ) , 5 ) ;
165- assert ! ( mut_struct. fields[ 2 ] . capacity( ) >= 5 ) ;
166- }
167-
168- #[ test]
169- fn test_try_into_mut_fails_first_field ( ) {
170- // Create a bool field with shared ownership (cloned to have Arc count > 1).
171- let bool_field: Vector = BoolVectorMut :: from_iter ( [ true , false , true ] )
172- . freeze ( )
173- . into ( ) ;
174- let bool_field_clone = bool_field. clone ( ) ;
175-
176- let null_field: Vector = NullVector :: new ( 3 ) . into ( ) ;
177- let prim_field: Vector = PVectorMut :: < i32 > :: from_iter ( [ 1 , 2 , 3 ] ) . freeze ( ) . into ( ) ;
178-
179- // Create a struct with the cloned bool field as the first field.
180- let struct_vec = create_struct_vector ( vec ! [ bool_field_clone, null_field, prim_field] , 3 , 3 ) ;
181-
182- // Attempt to convert to mutable.
183- let result = struct_vec. try_into_mut ( ) ;
184-
185- // Should fail since the first field has shared ownership.
186- assert ! ( result. is_err( ) ) ;
187-
188- // Keep the original alive to ensure shared ownership is maintained.
189- drop ( bool_field) ;
190-
191- let recovered_struct = result. unwrap_err ( ) ;
192-
193- // Verify the recovered struct has all 3 fields.
194- assert_eq ! ( recovered_struct. fields. len( ) , 3 ) ;
195- assert_eq ! ( recovered_struct. len( ) , 3 ) ;
196- assert_eq ! ( recovered_struct. capacity, 3 ) ;
197-
198- // Verify field types are preserved.
199- assert ! ( matches!( recovered_struct. fields[ 0 ] , Vector :: Bool ( _) ) ) ;
200- assert ! ( matches!( recovered_struct. fields[ 1 ] , Vector :: Null ( _) ) ) ;
201- assert ! ( matches!( recovered_struct. fields[ 2 ] , Vector :: Primitive ( _) ) ) ;
202- }
203-
204- #[ test]
205- fn test_try_into_mut_fails_middle_field ( ) {
206- // Create a primitive field with shared ownership (cloned).
207- let prim_field: Vector = PVectorMut :: < i32 > :: from_iter ( [ 100 , 200 , 300 , 400 ] )
208- . freeze ( )
209- . into ( ) ;
210- let prim_field_clone = prim_field. clone ( ) ;
211-
212- let bool_field: Vector = BoolVectorMut :: from_iter ( [ true , false , true , false ] )
213- . freeze ( )
214- . into ( ) ;
215- let null_field: Vector = NullVector :: new ( 4 ) . into ( ) ;
216-
217- // Create a struct with the cloned primitive field as the middle field.
218- let struct_vec = create_struct_vector ( vec ! [ bool_field, prim_field_clone, null_field] , 4 , 4 ) ;
219-
220- // Attempt to convert to mutable.
221- let result = struct_vec. try_into_mut ( ) ;
222-
223- // Should fail since the middle field has shared ownership.
224- assert ! ( result. is_err( ) ) ;
225-
226- // Keep the original alive to ensure shared ownership is maintained.
227- drop ( prim_field) ;
228-
229- let recovered_struct = result. unwrap_err ( ) ;
230-
231- // Verify all 3 fields are present in the recovered struct.
232- assert_eq ! ( recovered_struct. fields. len( ) , 3 ) ;
233- assert_eq ! ( recovered_struct. len( ) , 4 ) ;
234- assert_eq ! ( recovered_struct. capacity, 4 ) ;
235-
236- // Verify field types and order are preserved.
237- // The first field was converted to mutable then frozen back, so it should still be bool.
238- assert ! ( matches!( recovered_struct. fields[ 0 ] , Vector :: Bool ( _) ) ) ;
239- assert ! ( matches!( recovered_struct. fields[ 1 ] , Vector :: Primitive ( _) ) ) ;
240- assert ! ( matches!( recovered_struct. fields[ 2 ] , Vector :: Null ( _) ) ) ;
241- }
242-
243- #[ test]
244- fn test_try_into_mut_fails_last_field ( ) {
245- // Create a null field with "shared ownership" (though NullVector always succeeds, we test
246- // the pattern by cloning a bool vector).
247- let bool_field_last: Vector = BoolVectorMut :: from_iter ( [ true , true ] ) . freeze ( ) . into ( ) ;
248- let bool_field_last_clone = bool_field_last. clone ( ) ;
249-
250- let null_field: Vector = NullVector :: new ( 2 ) . into ( ) ;
251- let prim_field: Vector = PVectorMut :: < u64 > :: from_iter ( [ 1000 , 2000 ] ) . freeze ( ) . into ( ) ;
252-
253- // Create a struct with the cloned bool field as the last field.
254- let struct_vec =
255- create_struct_vector ( vec ! [ null_field, prim_field, bool_field_last_clone] , 2 , 2 ) ;
256-
257- // Attempt to convert to mutable.
258- let result = struct_vec. try_into_mut ( ) ;
259-
260- // Should fail since the last field has shared ownership.
261- assert ! ( result. is_err( ) ) ;
262-
263- // Keep the original alive to ensure shared ownership is maintained.
264- drop ( bool_field_last) ;
265-
266- let recovered_struct = result. unwrap_err ( ) ;
267-
268- // Verify all 3 fields are present.
269- assert_eq ! ( recovered_struct. fields. len( ) , 3 ) ;
270- assert_eq ! ( recovered_struct. len( ) , 2 ) ;
271- assert_eq ! ( recovered_struct. capacity, 2 ) ;
272-
273- // Verify field types are preserved.
274- // The first two fields were converted to mutable then frozen back.
275- assert ! ( matches!( recovered_struct. fields[ 0 ] , Vector :: Null ( _) ) ) ;
276- assert ! ( matches!( recovered_struct. fields[ 1 ] , Vector :: Primitive ( _) ) ) ;
277- assert ! ( matches!( recovered_struct. fields[ 2 ] , Vector :: Bool ( _) ) ) ;
278- }
279-
280- #[ test]
281- fn test_try_into_mut_nested_struct ( ) {
282- // Create a nested struct: a `StructVector` containing other `StructVector`s as fields.
283- let inner_struct1: Vector = create_struct_vector (
284- vec ! [
285- NullVector :: new( 3 ) . into( ) ,
286- BoolVectorMut :: from_iter( [ true , false , true ] )
287- . freeze( )
288- . into( ) ,
289- ] ,
290- 3 ,
291- 3 ,
292- )
293- . into ( ) ;
294-
295- let inner_struct2: Vector = create_struct_vector (
296- vec ! [ PVectorMut :: <i32 >:: from_iter( [ 1 , 2 , 3 ] ) . freeze( ) . into( ) ] ,
297- 3 ,
298- 3 ,
299- )
300- . into ( ) ;
301-
302- let outer_struct = create_struct_vector ( vec ! [ inner_struct1, inner_struct2] , 3 , 3 ) ;
303-
304- // Attempt to convert to mutable.
305- let result = outer_struct. try_into_mut ( ) ;
306-
307- // Should succeed once `StructVectorMut` is fully implemented.
308- assert ! ( result. is_ok( ) ) ;
309-
310- let mut_struct = result. unwrap ( ) ;
311- assert_eq ! ( mut_struct. len( ) , 3 ) ;
312- assert_eq ! ( mut_struct. fields. len( ) , 2 ) ;
313-
314- // Verify nested structs are converted correctly.
315- assert ! ( matches!( mut_struct. fields[ 0 ] , VectorMut :: Struct ( _) ) ) ;
316- assert ! ( matches!( mut_struct. fields[ 1 ] , VectorMut :: Struct ( _) ) ) ;
317- }
318- }
0 commit comments