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