vortex_layout/layouts/struct_/
mod.rs1mod reader;
5
6use std::sync::Arc;
7
8use reader::StructReader;
9use vortex_array::DeserializeMetadata;
10use vortex_array::EmptyMetadata;
11use vortex_array::dtype::DType;
12use vortex_array::dtype::Field;
13use vortex_array::dtype::FieldMask;
14use vortex_array::dtype::Nullability;
15use vortex_array::dtype::StructFields;
16use vortex_error::VortexExpect;
17use vortex_error::VortexResult;
18use vortex_error::vortex_bail;
19use vortex_error::vortex_ensure;
20use vortex_error::vortex_err;
21use vortex_session::SessionExt;
22use vortex_session::VortexSession;
23use vortex_session::registry::CachedId;
24
25use crate::LayoutBuildContext;
26use crate::LayoutChildType;
27use crate::LayoutEncodingRef;
28use crate::LayoutId;
29use crate::LayoutReaderRef;
30use crate::LayoutRef;
31use crate::VTable;
32use crate::children::LayoutChildren;
33use crate::children::OwnedLayoutChildren;
34use crate::segments::SegmentId;
35use crate::segments::SegmentSource;
36use crate::vtable;
37
38vtable!(Struct);
39
40impl VTable for Struct {
41 type Layout = StructLayout;
42 type Encoding = StructLayoutEncoding;
43 type Metadata = EmptyMetadata;
44
45 fn id(_encoding: &Self::Encoding) -> LayoutId {
46 static ID: CachedId = CachedId::new("vortex.struct");
47 *ID
48 }
49
50 fn encoding(_layout: &Self::Layout) -> LayoutEncodingRef {
51 LayoutEncodingRef::new_ref(StructLayoutEncoding.as_ref())
52 }
53
54 fn row_count(layout: &Self::Layout) -> u64 {
55 layout.row_count
56 }
57
58 fn dtype(layout: &Self::Layout) -> &DType {
59 &layout.dtype
60 }
61
62 fn metadata(_layout: &Self::Layout) -> Self::Metadata {
63 EmptyMetadata
64 }
65
66 fn segment_ids(_layout: &Self::Layout) -> Vec<SegmentId> {
67 vec![]
68 }
69
70 fn nchildren(layout: &Self::Layout) -> usize {
71 let validity_children = if layout.dtype.is_nullable() { 1 } else { 0 };
72 layout.struct_fields().nfields() + validity_children
73 }
74
75 fn child(layout: &Self::Layout, index: usize) -> VortexResult<LayoutRef> {
76 let schema_index = if layout.dtype.is_nullable() {
77 index.saturating_sub(1)
78 } else {
79 index
80 };
81
82 let child_dtype = if index == 0 && layout.dtype.is_nullable() {
83 DType::Bool(Nullability::NonNullable)
84 } else {
85 layout
86 .struct_fields()
87 .field_by_index(schema_index)
88 .ok_or_else(|| vortex_err!("Missing field {schema_index}"))?
89 };
90
91 layout.children.child(index, &child_dtype)
92 }
93
94 fn child_type(layout: &Self::Layout, idx: usize) -> LayoutChildType {
95 let schema_index = if layout.dtype.is_nullable() {
96 idx.saturating_sub(1)
97 } else {
98 idx
99 };
100
101 if idx == 0 && layout.dtype.is_nullable() {
102 LayoutChildType::Auxiliary("validity".into())
103 } else {
104 LayoutChildType::Field(
105 layout
106 .struct_fields()
107 .field_name(schema_index)
108 .vortex_expect("Field index out of bounds")
109 .clone(),
110 )
111 }
112 }
113
114 fn new_reader(
115 layout: &Self::Layout,
116 name: Arc<str>,
117 segment_source: Arc<dyn SegmentSource>,
118 session: &VortexSession,
119 ctx: &crate::LayoutReaderContext,
120 ) -> VortexResult<LayoutReaderRef> {
121 Ok(Arc::new(StructReader::try_new(
122 layout.clone(),
123 name,
124 segment_source,
125 session.session(),
126 ctx.clone(),
127 )?))
128 }
129
130 fn build(
131 _encoding: &Self::Encoding,
132 dtype: &DType,
133 row_count: u64,
134 _metadata: &<Self::Metadata as DeserializeMetadata>::Output,
135 _segment_ids: Vec<SegmentId>,
136 children: &dyn LayoutChildren,
137 _build_ctx: &LayoutBuildContext<'_>,
138 ) -> VortexResult<Self::Layout> {
139 let struct_dt = dtype
140 .as_struct_fields_opt()
141 .ok_or_else(|| vortex_err!("Expected struct dtype"))?;
142
143 let expected_children = struct_dt.nfields() + (dtype.is_nullable() as usize);
144 vortex_ensure!(
145 children.nchildren() == expected_children,
146 "Struct layout has {} children, but dtype has {} fields",
147 children.nchildren(),
148 struct_dt.nfields()
149 );
150
151 Ok(StructLayout {
152 row_count,
153 dtype: dtype.clone(),
154 children: children.to_arc(),
155 })
156 }
157
158 fn with_children(layout: &mut Self::Layout, children: Vec<LayoutRef>) -> VortexResult<()> {
159 let struct_dt = layout
160 .dtype
161 .as_struct_fields_opt()
162 .ok_or_else(|| vortex_err!("Expected struct dtype"))?;
163
164 let expected_children = struct_dt.nfields() + (layout.dtype.is_nullable() as usize);
165 vortex_ensure!(
166 children.len() == expected_children,
167 "StructLayout expects {} children, got {}",
168 expected_children,
169 children.len()
170 );
171
172 layout.children = OwnedLayoutChildren::layout_children(children);
173 Ok(())
174 }
175}
176
177#[derive(Debug)]
178pub struct StructLayoutEncoding;
179
180#[derive(Clone, Debug)]
184pub struct StructLayout {
185 row_count: u64,
186 dtype: DType,
187 children: Arc<dyn LayoutChildren>,
188}
189
190impl StructLayout {
191 pub fn new(row_count: u64, dtype: DType, children: Vec<LayoutRef>) -> Self {
192 Self {
193 row_count,
194 dtype,
195 children: OwnedLayoutChildren::layout_children(children),
196 }
197 }
198
199 pub fn struct_fields(&self) -> &StructFields {
200 self.dtype
201 .as_struct_fields_opt()
202 .vortex_expect("Struct layout dtype must be a struct")
203 }
204
205 #[inline]
206 pub fn row_count(&self) -> u64 {
207 self.row_count
208 }
209
210 #[inline]
211 pub fn children(&self) -> &Arc<dyn LayoutChildren> {
212 &self.children
213 }
214
215 pub fn matching_fields<F>(&self, field_mask: &[FieldMask], mut per_child: F) -> VortexResult<()>
216 where
217 F: FnMut(FieldMask, usize) -> VortexResult<()>,
218 {
219 if field_mask.iter().any(|mask| mask.matches_all()) {
221 for idx in 0..self.struct_fields().nfields() {
222 per_child(FieldMask::All, idx)?;
223 }
224 return Ok(());
225 }
226
227 for path in field_mask {
229 let Some(field) = path.starting_field()? else {
230 continue;
232 };
233 let Field::Name(field_name) = field else {
234 vortex_bail!("Expected field name, got {field:?}");
235 };
236 let idx = self
237 .struct_fields()
238 .find(field_name)
239 .ok_or_else(|| vortex_err!("Field not found: {field_name}"))?;
240
241 per_child(path.clone().step_into()?, idx)?;
242 }
243
244 Ok(())
245 }
246}