From 35197158a09a7cb3f6e854b6fcddd269b1faf228 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 24 Jul 2026 17:02:20 +0100 Subject: [PATCH 1/2] refactor(array): own struct field vectors Signed-off-by: Joe Isaacs --- vortex-array/src/arrays/struct_/array.rs | 23 +++++++++---------- .../src/arrays/struct_/compute/mask.rs | 2 +- vortex-array/src/canonical.rs | 8 +++---- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/vortex-array/src/arrays/struct_/array.rs b/vortex-array/src/arrays/struct_/array.rs index 8b939deb911..f8ada53a4a3 100644 --- a/vortex-array/src/arrays/struct_/array.rs +++ b/vortex-array/src/arrays/struct_/array.rs @@ -3,7 +3,6 @@ use std::borrow::Borrow; use std::iter::once; -use std::sync::Arc; use itertools::Itertools; use vortex_error::VortexExpect; @@ -159,7 +158,7 @@ pub(super) const FIELDS_OFFSET: usize = 1; /// ``` pub struct StructDataParts { pub struct_fields: StructFields, - pub fields: Arc<[ArrayRef]>, + pub fields: Vec, pub validity: Validity, } @@ -198,7 +197,7 @@ pub trait StructArrayExt: TypedArrayRef { .map(|s| s.as_ref().vortex_expect("StructArray field slot")) } - fn unmasked_fields(&self) -> Arc<[ArrayRef]> { + fn unmasked_fields(&self) -> Vec { self.iter_unmasked_fields().cloned().collect() } @@ -235,7 +234,7 @@ impl Array { /// Creates a new `StructArray`. pub fn new( names: FieldNames, - fields: impl Into>, + fields: impl IntoIterator, length: usize, validity: Validity, ) -> Self { @@ -246,11 +245,11 @@ impl Array { /// Constructs a new `StructArray`. pub fn try_new( names: FieldNames, - fields: impl Into>, + fields: impl IntoIterator, length: usize, validity: Validity, ) -> VortexResult { - let fields = fields.into(); + let fields: Vec<_> = fields.into_iter().collect(); let field_dtypes: Vec<_> = fields.iter().map(|d| d.dtype().clone()).collect(); let dtype = StructFields::new(names, field_dtypes); let slots = make_struct_slots(&fields, &validity, length); @@ -271,12 +270,12 @@ impl Array { /// /// Caller must ensure the field arrays match the supplied dtype, length, and validity. pub unsafe fn new_unchecked( - fields: impl Into>, + fields: impl IntoIterator, dtype: StructFields, length: usize, validity: Validity, ) -> Self { - let fields = fields.into(); + let fields: Vec<_> = fields.into_iter().collect(); let outer_dtype = DType::Struct(dtype, validity.nullability()); let slots = make_struct_slots(&fields, &validity, length); unsafe { @@ -288,12 +287,12 @@ impl Array { /// Constructs a new `StructArray` with an explicit dtype. pub fn try_new_with_dtype( - fields: impl Into>, + fields: impl IntoIterator, dtype: StructFields, length: usize, validity: Validity, ) -> VortexResult { - let fields = fields.into(); + let fields: Vec<_> = fields.into_iter().collect(); let outer_dtype = DType::Struct(dtype, validity.nullability()); let slots = make_struct_slots(&fields, &validity, length); Array::try_from_parts( @@ -393,7 +392,7 @@ impl Array { // TODO(ngates): remove this... it doesn't help to consume self. pub fn into_data_parts(self) -> StructDataParts { - let fields: Arc<[ArrayRef]> = self.slots()[FIELDS_OFFSET..] + let fields: Vec = self.slots()[FIELDS_OFFSET..] .iter() .map(|s| s.as_ref().vortex_expect("StructArray field slot").clone()) .collect(); @@ -448,7 +447,7 @@ impl Array { let types = struct_dtype.fields().chain(once(array.dtype().clone())); let new_fields = StructFields::new(names.collect(), types.collect()); - let children: Arc<[ArrayRef]> = self.slots()[FIELDS_OFFSET..] + let children: Vec = self.slots()[FIELDS_OFFSET..] .iter() .map(|s| s.as_ref().vortex_expect("StructArray field slot").clone()) .chain(once(array)) diff --git a/vortex-array/src/arrays/struct_/compute/mask.rs b/vortex-array/src/arrays/struct_/compute/mask.rs index a36fa1743e1..0f428284454 100644 --- a/vortex-array/src/arrays/struct_/compute/mask.rs +++ b/vortex-array/src/arrays/struct_/compute/mask.rs @@ -15,7 +15,7 @@ use crate::validity::Validity; impl MaskReduce for Struct { fn mask(array: ArrayView<'_, Struct>, mask: &ArrayRef) -> VortexResult> { StructArray::try_new_with_dtype( - array.unmasked_fields().iter().cloned().collect::>(), + array.unmasked_fields(), array.struct_fields().clone(), array.len(), array.validity()?.and(Validity::Array(mask.clone()))?, diff --git a/vortex-array/src/canonical.rs b/vortex-array/src/canonical.rs index 79abbd00587..bc10c803633 100644 --- a/vortex-array/src/canonical.rs +++ b/vortex-array/src/canonical.rs @@ -228,7 +228,7 @@ impl Canonical { struct_dtype .fields() .map(|f| Canonical::empty(&f).into_array()) - .collect::>(), + .collect::>(), struct_dtype.clone(), 0, Validity::from(n), @@ -854,9 +854,9 @@ impl Executable for RecursiveCanonical { validity, } = st.into_data_parts(); let executed_fields = fields - .iter() - .map(|f| Ok(f.clone().execute::(ctx)?.0.into_array())) - .collect::>>()?; + .into_iter() + .map(|f| Ok(f.execute::(ctx)?.0.into_array())) + .collect::>>()?; Ok(RecursiveCanonical(Canonical::Struct(unsafe { StructArray::new_unchecked( From ecbc6cc7dd64227af7348362b6585ff9e3cd6568 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 24 Jul 2026 17:24:15 +0100 Subject: [PATCH 2/2] fix(duckdb): pass owned struct fields Signed-off-by: Joe Isaacs --- vortex-duckdb/src/convert/vector.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vortex-duckdb/src/convert/vector.rs b/vortex-duckdb/src/convert/vector.rs index a7a0966f0e4..76d8f92f48e 100644 --- a/vortex-duckdb/src/convert/vector.rs +++ b/vortex-duckdb/src/convert/vector.rs @@ -1,8 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors -use std::sync::Arc; - use num_traits::AsPrimitive; use vortex::array::ArrayRef; use vortex::array::IntoArray; @@ -377,7 +375,7 @@ pub fn data_chunk_to_vortex( vector.flatten(len); flat_vector_to_vortex(vector, len.as_()) }) - .collect::>>()?; + .collect::>>()?; StructArray::try_new( field_names.clone(), columns,