vortex_layout/layouts/list/
mod.rs1mod expr;
18mod reader;
19pub mod writer;
20
21use std::sync::Arc;
22
23use reader::ListReader;
24use vortex_array::DeserializeMetadata;
25use vortex_array::ProstMetadata;
26use vortex_array::dtype::DType;
27use vortex_array::dtype::Nullability;
28use vortex_array::dtype::PType;
29use vortex_error::VortexExpect;
30use vortex_error::VortexResult;
31use vortex_error::vortex_bail;
32use vortex_error::vortex_ensure_eq;
33use vortex_error::vortex_err;
34use vortex_error::vortex_panic;
35use vortex_session::VortexSession;
36use vortex_session::registry::CachedId;
37
38use crate::LayoutBuildContext;
39use crate::LayoutChildType;
40use crate::LayoutEncodingRef;
41use crate::LayoutId;
42use crate::LayoutReaderContext;
43use crate::LayoutReaderRef;
44use crate::LayoutRef;
45use crate::VTable;
46use crate::children::LayoutChildren;
47use crate::segments::SegmentId;
48use crate::segments::SegmentSource;
49use crate::vtable;
50
51pub const ELEMENTS_CHILD_INDEX: usize = 0;
53pub const OFFSETS_CHILD_INDEX: usize = 1;
55pub const VALIDITY_CHILD_INDEX: usize = 2;
57
58pub const NUM_CHILDREN_NON_NULLABLE: usize = 2;
60
61vtable!(List);
62
63impl VTable for List {
64 type Layout = ListLayout;
65 type Encoding = ListLayoutEncoding;
66 type Metadata = ProstMetadata<ListLayoutMetadata>;
67
68 fn id(_encoding: &Self::Encoding) -> LayoutId {
69 static ID: CachedId = CachedId::new("vortex.list");
70 *ID
71 }
72
73 fn encoding(_layout: &Self::Layout) -> LayoutEncodingRef {
74 LayoutEncodingRef::new_ref(ListLayoutEncoding.as_ref())
75 }
76
77 fn row_count(layout: &Self::Layout) -> u64 {
78 layout.row_count()
79 }
80
81 fn dtype(layout: &Self::Layout) -> &DType {
82 &layout.dtype
83 }
84
85 fn metadata(layout: &Self::Layout) -> Self::Metadata {
86 ProstMetadata(ListLayoutMetadata::new(layout.offsets_ptype()))
87 }
88
89 fn segment_ids(_layout: &Self::Layout) -> Vec<SegmentId> {
90 vec![]
91 }
92
93 fn nchildren(layout: &Self::Layout) -> usize {
94 if layout.dtype.is_nullable() {
95 NUM_CHILDREN_NON_NULLABLE + 1
96 } else {
97 NUM_CHILDREN_NON_NULLABLE
98 }
99 }
100
101 fn child(layout: &Self::Layout, idx: usize) -> VortexResult<LayoutRef> {
102 match (idx, layout.validity.as_ref()) {
103 (ELEMENTS_CHILD_INDEX, _) => Ok(Arc::clone(&layout.elements)),
104 (OFFSETS_CHILD_INDEX, _) => Ok(Arc::clone(&layout.offsets)),
105 (VALIDITY_CHILD_INDEX, Some(validity)) => Ok(Arc::clone(validity)),
106 _ => vortex_bail!("Invalid child index {idx} for ListLayout"),
107 }
108 }
109
110 fn child_type(layout: &Self::Layout, idx: usize) -> LayoutChildType {
111 match (idx, layout.validity.is_some()) {
112 (ELEMENTS_CHILD_INDEX, _) => LayoutChildType::Auxiliary("elements".into()),
113 (OFFSETS_CHILD_INDEX, _) => LayoutChildType::Auxiliary("offsets".into()),
114 (VALIDITY_CHILD_INDEX, true) => LayoutChildType::Auxiliary("validity".into()),
115 _ => vortex_panic!("Invalid child index {idx} for ListLayout"),
116 }
117 }
118
119 fn new_reader(
120 layout: &Self::Layout,
121 name: Arc<str>,
122 segment_source: Arc<dyn SegmentSource>,
123 session: &VortexSession,
124 ctx: &LayoutReaderContext,
125 ) -> VortexResult<LayoutReaderRef> {
126 Ok(Arc::new(ListReader::try_new(
127 layout.clone(),
128 name,
129 segment_source,
130 session.clone(),
131 ctx,
132 )?))
133 }
134
135 fn build(
136 _encoding: &Self::Encoding,
137 dtype: &DType,
138 _row_count: u64,
139 metadata: &<Self::Metadata as DeserializeMetadata>::Output,
140 _segment_ids: Vec<SegmentId>,
141 children: &dyn LayoutChildren,
142 _ctx: &LayoutBuildContext<'_>,
143 ) -> VortexResult<Self::Layout> {
144 validate_children(dtype, children.nchildren())?;
145
146 let elements_dtype = dtype
147 .as_list_element_opt()
148 .ok_or_else(|| vortex_err!("ListLayout requires a List dtype, got {dtype}"))?;
149 let elements = children.child(ELEMENTS_CHILD_INDEX, elements_dtype.as_ref())?;
150
151 let offsets_dtype = DType::Primitive(metadata.offsets_ptype(), Nullability::NonNullable);
152 let offsets = children.child(OFFSETS_CHILD_INDEX, &offsets_dtype)?;
153
154 let validity = dtype
155 .is_nullable()
156 .then(|| children.child(VALIDITY_CHILD_INDEX, &DType::Bool(Nullability::NonNullable)))
157 .transpose()?;
158
159 Ok(ListLayout {
160 dtype: dtype.clone(),
161 elements,
162 offsets,
163 validity,
164 })
165 }
166
167 fn with_children(layout: &mut Self::Layout, children: Vec<LayoutRef>) -> VortexResult<()> {
168 validate_children(layout.dtype(), children.len())?;
169
170 let mut iter = children.into_iter();
171 layout.elements = iter
172 .next()
173 .ok_or_else(|| vortex_err!("missing elements child"))?;
174 layout.offsets = iter
175 .next()
176 .ok_or_else(|| vortex_err!("missing offsets child"))?;
177 layout.validity = layout
178 .dtype
179 .is_nullable()
180 .then(|| {
181 iter.next()
182 .ok_or_else(|| vortex_err!("missing validity child"))
183 })
184 .transpose()?;
185 Ok(())
186 }
187}
188
189fn validate_children(dtype: &DType, n_children: usize) -> VortexResult<()> {
191 let expected = if dtype.is_nullable() {
192 NUM_CHILDREN_NON_NULLABLE + 1
193 } else {
194 NUM_CHILDREN_NON_NULLABLE
195 };
196
197 vortex_ensure_eq!(n_children, expected);
198 Ok(())
199}
200
201#[derive(Debug)]
202pub struct ListLayoutEncoding;
203
204#[derive(Clone, Debug)]
206pub struct ListLayout {
207 dtype: DType,
208 elements: LayoutRef,
209 offsets: LayoutRef,
210 validity: Option<LayoutRef>,
211}
212
213impl ListLayout {
214 pub fn new(
224 dtype: DType,
225 elements: LayoutRef,
226 offsets: LayoutRef,
227 validity: Option<LayoutRef>,
228 ) -> Self {
229 Self {
230 dtype,
231 elements,
232 offsets,
233 validity,
234 }
235 }
236
237 #[inline]
239 pub fn row_count(&self) -> u64 {
240 self.offsets.row_count().saturating_sub(1)
241 }
242
243 #[inline]
244 pub fn elements(&self) -> &LayoutRef {
245 &self.elements
246 }
247
248 #[inline]
249 pub fn offsets(&self) -> &LayoutRef {
250 &self.offsets
251 }
252
253 #[inline]
254 pub fn validity(&self) -> Option<&LayoutRef> {
255 self.validity.as_ref()
256 }
257
258 #[inline]
260 pub fn offsets_ptype(&self) -> PType {
261 self.offsets.dtype().as_ptype()
262 }
263
264 pub fn elements_dtype(&self) -> &DType {
266 self.dtype
267 .as_list_element_opt()
268 .vortex_expect("ListLayout dtype must be a List")
269 }
270}
271
272#[derive(prost::Message)]
273pub struct ListLayoutMetadata {
274 #[prost(enumeration = "PType", tag = "1")]
275 offsets_ptype: i32,
276}
277
278impl ListLayoutMetadata {
279 pub fn new(offsets_ptype: PType) -> Self {
280 let mut metadata = Self::default();
281 metadata.set_offsets_ptype(offsets_ptype);
282 metadata
283 }
284}