Skip to content

Commit 9e7d964

Browse files
committed
add StructVector ops implementation
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
1 parent b5f46d3 commit 9e7d964

File tree

1 file changed

+279
-3
lines changed

1 file changed

+279
-3
lines changed

vortex-vector/src/struct_/vector.rs

Lines changed: 279 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
use vortex_mask::Mask;
77

8-
use crate::{StructVectorMut, VectorOps};
8+
use crate::{StructVectorMut, Vector, VectorMutOps, VectorOps};
99

1010
/// An immutable vector of boolean values.
1111
///
@@ -15,15 +15,35 @@ use crate::{StructVectorMut, VectorOps};
1515
/// See the documentation for [`StructVectorMut`] for more information.
1616
#[derive(Debug, Clone)]
1717
pub struct StructVector {
18+
/// The fields of the `StructVector`, each stored column-wise as a [`Vector`].
19+
pub(super) fields: Box<[Vector]>,
20+
21+
/// The length of the vector (which is the same as all field vectors).
22+
///
23+
/// This is stored here as a convenience.
24+
pub(super) len: usize,
25+
26+
/// The capacity of the vector (which is the same as all field vectors).
27+
///
28+
/// This is stored here as a convenience for converting to/from a [`StructVectorMut`].
29+
pub(super) capacity: usize,
30+
1831
/// The validity mask (where `true` represents an element is **not** null).
1932
pub(super) validity: Mask,
2033
}
2134

35+
impl StructVector {
36+
/// Returns the fields of the `StructVector`, each stored column-wise as a [`Vector`].
37+
pub fn fields(&self) -> &[Vector] {
38+
self.fields.as_ref()
39+
}
40+
}
41+
2242
impl VectorOps for StructVector {
2343
type Mutable = StructVectorMut;
2444

2545
fn len(&self) -> usize {
26-
todo!()
46+
self.len
2747
}
2848

2949
fn validity(&self) -> &Mask {
@@ -34,6 +54,262 @@ impl VectorOps for StructVector {
3454
where
3555
Self: Sized,
3656
{
37-
todo!()
57+
let validity = match self.validity.try_into_mut() {
58+
Ok(validity) => validity,
59+
Err(validity) => {
60+
return Err(StructVector { validity, ..self });
61+
}
62+
};
63+
64+
// Convert all of the remaining fields to mutable, if possible.
65+
let mut mutable_fields = Vec::with_capacity(self.fields.len());
66+
let mut fields_iter = self.fields.into_iter();
67+
68+
while let Some(field) = fields_iter.next() {
69+
match field.try_into_mut() {
70+
Ok(mutable_field) => {
71+
// We were able to take ownership of the field vector, so add it and keep going.
72+
mutable_fields.push(mutable_field);
73+
}
74+
Err(immutable_field) => {
75+
// We were unable to take ownership, so we must re-freeze all of the fields
76+
// vectors we took ownership over and reconstruct the original `StructVector`.
77+
78+
let mut all_fields: Vec<Vector> = mutable_fields
79+
.into_iter()
80+
.map(|mut_field| mut_field.freeze())
81+
.collect();
82+
83+
all_fields.push(immutable_field);
84+
all_fields.extend(fields_iter);
85+
86+
return Err(StructVector {
87+
fields: all_fields.into_boxed_slice(),
88+
len: self.len,
89+
capacity: self.capacity,
90+
validity: validity.freeze(),
91+
});
92+
}
93+
}
94+
}
95+
96+
Ok(StructVectorMut {
97+
fields: mutable_fields,
98+
len: self.len,
99+
capacity: self.capacity,
100+
validity,
101+
})
102+
}
103+
}
104+
105+
#[cfg(test)]
106+
mod tests {
107+
use vortex_mask::Mask;
108+
109+
use super::*;
110+
use crate::{BoolVectorMut, NullVector, PVectorMut, VectorMut};
111+
112+
// TODO(connor): Make sure to test actual logic instead of just lengths and capacity.
113+
114+
/// Helper function to create a `StructVector` with the given fields.
115+
fn create_struct_vector(fields: Vec<Vector>, len: usize, capacity: usize) -> StructVector {
116+
StructVector {
117+
fields: fields.into_boxed_slice(),
118+
len,
119+
capacity,
120+
validity: Mask::AllTrue(len),
121+
}
122+
}
123+
124+
#[test]
125+
fn test_try_into_mut_success() {
126+
// Create a `StructVector` with 3 different field types (null, bool, primitive).
127+
let null_field: Vector = NullVector::new(5).into();
128+
let bool_field: Vector = BoolVectorMut::from_iter([true, false, true, false, true])
129+
.freeze()
130+
.into();
131+
let prim_field: Vector = PVectorMut::<i32>::from_iter([10, 20, 30, 40, 50])
132+
.freeze()
133+
.into();
134+
135+
let struct_vec = create_struct_vector(vec![null_field, bool_field, prim_field], 5, 5);
136+
137+
// Attempt to convert to mutable.
138+
let result = struct_vec.try_into_mut();
139+
140+
// Should succeed since all fields have unique ownership.
141+
assert!(result.is_ok());
142+
143+
let mut_struct = result.unwrap();
144+
145+
// Verify the mutable struct has correct length and capacity.
146+
assert_eq!(mut_struct.len(), 5);
147+
assert_eq!(mut_struct.capacity(), 5);
148+
149+
// Verify that we have 3 fields.
150+
assert_eq!(mut_struct.fields.len(), 3);
151+
152+
// Verify each field has the correct type and length.
153+
assert!(matches!(mut_struct.fields[0], VectorMut::Null(_)));
154+
assert_eq!(mut_struct.fields[0].len(), 5);
155+
156+
assert!(matches!(mut_struct.fields[1], VectorMut::Bool(_)));
157+
assert_eq!(mut_struct.fields[1].len(), 5);
158+
assert!(mut_struct.fields[1].capacity() >= 5);
159+
160+
assert!(matches!(mut_struct.fields[2], VectorMut::Primitive(_)));
161+
assert_eq!(mut_struct.fields[2].len(), 5);
162+
assert!(mut_struct.fields[2].capacity() >= 5);
163+
}
164+
165+
#[test]
166+
fn test_try_into_mut_fails_first_field() {
167+
// Create a bool field with shared ownership (cloned to have Arc count > 1).
168+
let bool_field: Vector = BoolVectorMut::from_iter([true, false, true])
169+
.freeze()
170+
.into();
171+
let bool_field_clone = bool_field.clone();
172+
173+
let null_field: Vector = NullVector::new(3).into();
174+
let prim_field: Vector = PVectorMut::<i32>::from_iter([1, 2, 3]).freeze().into();
175+
176+
// Create a struct with the cloned bool field as the first field.
177+
let struct_vec = create_struct_vector(vec![bool_field_clone, null_field, prim_field], 3, 3);
178+
179+
// Attempt to convert to mutable.
180+
let result = struct_vec.try_into_mut();
181+
182+
// Should fail since the first field has shared ownership.
183+
assert!(result.is_err());
184+
185+
// Keep the original alive to ensure shared ownership is maintained.
186+
drop(bool_field);
187+
188+
let recovered_struct = result.unwrap_err();
189+
190+
// Verify the recovered struct has all 3 fields.
191+
assert_eq!(recovered_struct.fields.len(), 3);
192+
assert_eq!(recovered_struct.len(), 3);
193+
assert_eq!(recovered_struct.capacity, 3);
194+
195+
// Verify field types are preserved.
196+
assert!(matches!(recovered_struct.fields[0], Vector::Bool(_)));
197+
assert!(matches!(recovered_struct.fields[1], Vector::Null(_)));
198+
assert!(matches!(recovered_struct.fields[2], Vector::Primitive(_)));
199+
}
200+
201+
#[test]
202+
fn test_try_into_mut_fails_middle_field() {
203+
// Create a primitive field with shared ownership (cloned).
204+
let prim_field: Vector = PVectorMut::<i32>::from_iter([100, 200, 300, 400])
205+
.freeze()
206+
.into();
207+
let prim_field_clone = prim_field.clone();
208+
209+
let bool_field: Vector = BoolVectorMut::from_iter([true, false, true, false])
210+
.freeze()
211+
.into();
212+
let null_field: Vector = NullVector::new(4).into();
213+
214+
// Create a struct with the cloned primitive field as the middle field.
215+
let struct_vec = create_struct_vector(vec![bool_field, prim_field_clone, null_field], 4, 4);
216+
217+
// Attempt to convert to mutable.
218+
let result = struct_vec.try_into_mut();
219+
220+
// Should fail since the middle field has shared ownership.
221+
assert!(result.is_err());
222+
223+
// Keep the original alive to ensure shared ownership is maintained.
224+
drop(prim_field);
225+
226+
let recovered_struct = result.unwrap_err();
227+
228+
// Verify all 3 fields are present in the recovered struct.
229+
assert_eq!(recovered_struct.fields.len(), 3);
230+
assert_eq!(recovered_struct.len(), 4);
231+
assert_eq!(recovered_struct.capacity, 4);
232+
233+
// Verify field types and order are preserved.
234+
// The first field was converted to mutable then frozen back, so it should still be bool.
235+
assert!(matches!(recovered_struct.fields[0], Vector::Bool(_)));
236+
assert!(matches!(recovered_struct.fields[1], Vector::Primitive(_)));
237+
assert!(matches!(recovered_struct.fields[2], Vector::Null(_)));
238+
}
239+
240+
#[test]
241+
fn test_try_into_mut_fails_last_field() {
242+
// Create a null field with "shared ownership" (though NullVector always succeeds, we test
243+
// the pattern by cloning a bool vector).
244+
let bool_field_last: Vector = BoolVectorMut::from_iter([true, true]).freeze().into();
245+
let bool_field_last_clone = bool_field_last.clone();
246+
247+
let null_field: Vector = NullVector::new(2).into();
248+
let prim_field: Vector = PVectorMut::<u64>::from_iter([1000, 2000]).freeze().into();
249+
250+
// Create a struct with the cloned bool field as the last field.
251+
let struct_vec =
252+
create_struct_vector(vec![null_field, prim_field, bool_field_last_clone], 2, 2);
253+
254+
// Attempt to convert to mutable.
255+
let result = struct_vec.try_into_mut();
256+
257+
// Should fail since the last field has shared ownership.
258+
assert!(result.is_err());
259+
260+
// Keep the original alive to ensure shared ownership is maintained.
261+
drop(bool_field_last);
262+
263+
let recovered_struct = result.unwrap_err();
264+
265+
// Verify all 3 fields are present.
266+
assert_eq!(recovered_struct.fields.len(), 3);
267+
assert_eq!(recovered_struct.len(), 2);
268+
assert_eq!(recovered_struct.capacity, 2);
269+
270+
// Verify field types are preserved.
271+
// The first two fields were converted to mutable then frozen back.
272+
assert!(matches!(recovered_struct.fields[0], Vector::Null(_)));
273+
assert!(matches!(recovered_struct.fields[1], Vector::Primitive(_)));
274+
assert!(matches!(recovered_struct.fields[2], Vector::Bool(_)));
275+
}
276+
277+
#[test]
278+
fn test_try_into_mut_nested_struct() {
279+
// Create a nested struct: a `StructVector` containing other `StructVector`s as fields.
280+
let inner_struct1: Vector = create_struct_vector(
281+
vec![
282+
NullVector::new(3).into(),
283+
BoolVectorMut::from_iter([true, false, true])
284+
.freeze()
285+
.into(),
286+
],
287+
3,
288+
3,
289+
)
290+
.into();
291+
292+
let inner_struct2: Vector = create_struct_vector(
293+
vec![PVectorMut::<i32>::from_iter([1, 2, 3]).freeze().into()],
294+
3,
295+
3,
296+
)
297+
.into();
298+
299+
let outer_struct = create_struct_vector(vec![inner_struct1, inner_struct2], 3, 3);
300+
301+
// Attempt to convert to mutable.
302+
let result = outer_struct.try_into_mut();
303+
304+
// Should succeed once `StructVectorMut` is fully implemented.
305+
assert!(result.is_ok());
306+
307+
let mut_struct = result.unwrap();
308+
assert_eq!(mut_struct.len(), 3);
309+
assert_eq!(mut_struct.fields.len(), 2);
310+
311+
// Verify nested structs are converted correctly.
312+
assert!(matches!(mut_struct.fields[0], VectorMut::Struct(_)));
313+
assert!(matches!(mut_struct.fields[1], VectorMut::Struct(_)));
38314
}
39315
}

0 commit comments

Comments
 (0)