Skip to main content

vortex_layout/
vtable.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::fmt::Debug;
5use std::sync::Arc;
6
7use vortex_array::SerializeMetadata;
8use vortex_array::dtype::DType;
9use vortex_error::VortexResult;
10use vortex_session::VortexSession;
11
12use crate::DynLayout;
13use crate::Layout;
14use crate::LayoutBuildContext;
15use crate::LayoutChildType;
16use crate::LayoutChildren;
17use crate::LayoutDeserializeArgs;
18use crate::LayoutId;
19use crate::LayoutParts;
20use crate::LayoutReaderContext;
21use crate::LayoutReaderRef;
22use crate::segments::SegmentId;
23use crate::segments::SegmentSource;
24
25/// Shared, erased handle to a layout tree node.
26pub type LayoutRef = Arc<dyn DynLayout>;
27
28/// Layout-specific behavior for a typed [`Layout`].
29///
30/// Common serialized fields are stored by [`Layout`]. Implementations own only their
31/// layout-specific data, metadata codec, child typing, and reader construction.
32pub trait VTable: 'static + Clone + Send + Sync + Debug {
33    /// Layout-specific data.
34    type LayoutData: 'static + Clone + Send + Sync + Debug;
35    /// Serialized metadata type.
36    type Metadata: SerializeMetadata + vortex_array::DeserializeMetadata + Debug;
37
38    /// Returns the globally unique layout ID.
39    fn id(&self) -> LayoutId;
40
41    /// Returns the serializable metadata for a layout.
42    fn metadata(layout: &Layout<Self>) -> Self::Metadata;
43
44    /// Deserialize and validate layout-specific data.
45    fn deserialize(
46        &self,
47        args: &LayoutDeserializeArgs<'_>,
48        metadata: &<Self::Metadata as vortex_array::DeserializeMetadata>::Output,
49    ) -> VortexResult<Self::LayoutData>;
50
51    /// Construct a typed layout from deserialized common fields.
52    fn build(
53        vtable: &Self,
54        dtype: &DType,
55        row_count: u64,
56        metadata: &<Self::Metadata as vortex_array::DeserializeMetadata>::Output,
57        segment_ids: Vec<SegmentId>,
58        children: &dyn LayoutChildren,
59        build_ctx: &LayoutBuildContext<'_>,
60    ) -> VortexResult<Layout<Self>> {
61        let args = LayoutDeserializeArgs {
62            session: build_ctx.session,
63            array_read_ctx: build_ctx.array_read_ctx,
64            dtype,
65            row_count,
66            segment_ids,
67            children,
68        };
69        let data = vtable.deserialize(&args, metadata)?;
70        Ok(LayoutParts::new(
71            vtable.clone(),
72            dtype.clone(),
73            row_count,
74            args.segment_ids,
75            children.to_arc(),
76            data,
77        )
78        .into_typed())
79    }
80
81    /// Returns the number of logical child *slots* of this layout.
82    ///
83    /// Slots are fixed logical positions: a given child always occupies the same slot index
84    /// regardless of which optional siblings are present. A slot may be absent (see
85    /// [`slot_to_child`](VTable::slot_to_child)), in which case it has no corresponding serialized
86    /// child. The default implementation reports one slot per serialized child, i.e. every slot is
87    /// always present.
88    fn nslots(layout: &Layout<Self>) -> usize {
89        layout.nchildren()
90    }
91
92    /// Maps a logical `slot` to the index of its serialized (dense) child, or `None` if the slot
93    /// is absent for this layout instance.
94    ///
95    /// Serialized children are stored densely (present-only), so an absent slot shifts the dense
96    /// indices of the slots that follow it. This mapping centralizes that arithmetic; the default
97    /// implementation is the identity, treating slot indices and dense child indices as equal.
98    fn slot_to_child(layout: &Layout<Self>, slot: usize) -> Option<usize> {
99        (slot < Self::nslots(layout)).then_some(slot)
100    }
101
102    /// Returns the expected dtype of the child in logical `slot`.
103    fn child_dtype(layout: &Layout<Self>, slot: usize) -> VortexResult<DType>;
104
105    /// Returns the relationship between the child in logical `slot` and its parent.
106    fn child_type(layout: &Layout<Self>, slot: usize) -> LayoutChildType;
107
108    /// Construct a reader for this layout.
109    fn new_reader(
110        layout: &Layout<Self>,
111        name: Arc<str>,
112        segment_source: Arc<dyn SegmentSource>,
113        session: &VortexSession,
114        ctx: &LayoutReaderContext,
115    ) -> VortexResult<LayoutReaderRef>;
116
117    /// Returns `true` if this layout is indivisible: its readers never register natural split
118    /// boundaries strictly inside their row range (see [`crate::LayoutReader::register_splits`]).
119    ///
120    /// Indivisible layouts — like flat, whose readers only ever push the end of the requested
121    /// range — let parent layouts skip materializing the child entirely during split collection.
122    fn is_indivisible(&self) -> bool {
123        false
124    }
125}