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::ops::Deref;
6use std::sync::Arc;
7
8use vortex_array::DeserializeMetadata;
9use vortex_array::SerializeMetadata;
10use vortex_array::dtype::DType;
11use vortex_error::VortexResult;
12use vortex_error::vortex_bail;
13use vortex_session::VortexSession;
14use vortex_session::registry::ReadContext;
15
16use crate::IntoLayout;
17use crate::Layout;
18use crate::LayoutChildType;
19use crate::LayoutEncoding;
20use crate::LayoutEncodingRef;
21use crate::LayoutId;
22use crate::LayoutReaderContext;
23use crate::LayoutReaderRef;
24use crate::LayoutRef;
25use crate::children::LayoutChildren;
26use crate::segments::SegmentId;
27use crate::segments::SegmentSource;
28
29pub trait VTable: 'static + Sized + Send + Sync + Debug {
30    type Layout: 'static + Send + Sync + Clone + Debug + Deref<Target = dyn Layout> + IntoLayout;
31    type Encoding: 'static + Send + Sync + Deref<Target = dyn LayoutEncoding>;
32    type Metadata: SerializeMetadata + DeserializeMetadata + Debug;
33
34    /// Returns the ID of the layout encoding.
35    fn id(encoding: &Self::Encoding) -> LayoutId;
36
37    /// Returns the encoding for the layout.
38    fn encoding(layout: &Self::Layout) -> LayoutEncodingRef;
39
40    /// Returns the row count for the layout reader.
41    fn row_count(layout: &Self::Layout) -> u64;
42
43    /// Returns the dtype for the layout reader.
44    fn dtype(layout: &Self::Layout) -> &DType;
45
46    /// Returns the metadata for the layout.
47    fn metadata(layout: &Self::Layout) -> Self::Metadata;
48
49    /// Returns the segment IDs for the layout.
50    fn segment_ids(layout: &Self::Layout) -> Vec<SegmentId>;
51
52    /// Returns the number of children for the layout.
53    fn nchildren(layout: &Self::Layout) -> usize;
54
55    /// Return the child at the given index.
56    fn child(layout: &Self::Layout, idx: usize) -> VortexResult<LayoutRef>;
57
58    /// Return the type of the child at the given index.
59    fn child_type(layout: &Self::Layout, idx: usize) -> LayoutChildType;
60
61    /// Create a new reader for the layout.
62    ///
63    /// **Layouts with children MUST propagate `ctx` to descendants** by passing it
64    /// through `Layout::new_reader` (or `LazyReaderChildren::new`) when constructing
65    /// child readers. If `ctx` is dropped at any link in the chain, ancestor-published
66    /// values won't reach affected descendants — a silent runtime regression for any
67    /// descendant that looked up an ancestor-published value via `ctx.get::<T>()`.
68    /// There is no compile-time check that catches this; reviewer discipline + the
69    /// integration tests in `vortex-layout` are the only safety net.
70    fn new_reader(
71        layout: &Self::Layout,
72        name: Arc<str>,
73        segment_source: Arc<dyn SegmentSource>,
74        session: &VortexSession,
75        ctx: &LayoutReaderContext,
76    ) -> VortexResult<LayoutReaderRef>;
77
78    /// Construct a new [`Layout`] from the provided parts.
79    fn build(
80        encoding: &Self::Encoding,
81        dtype: &DType,
82        row_count: u64,
83        metadata: &<Self::Metadata as DeserializeMetadata>::Output,
84        segment_ids: Vec<SegmentId>,
85        children: &dyn LayoutChildren,
86        ctx: &ReadContext,
87    ) -> VortexResult<Self::Layout>;
88
89    /// Replaces the children of the layout with the given layout references.
90    ///
91    /// The count and types of children must match the layout's requirements.
92    /// This method is used for transforming layout trees by replacing child layouts.
93    fn with_children(_layout: &mut Self::Layout, _children: Vec<LayoutRef>) -> VortexResult<()> {
94        vortex_bail!("with_children not implemented for this layout")
95    }
96}
97
98#[macro_export]
99macro_rules! vtable {
100    ($V:ident) => {
101        $crate::aliases::paste::paste! {
102            #[derive(Debug)]
103            pub struct $V;
104
105            impl AsRef<dyn $crate::Layout> for [<$V Layout>] {
106                fn as_ref(&self) -> &dyn $crate::Layout {
107                    // SAFETY: LayoutAdapter is #[repr(transparent)] over the Layout type,
108                    // which guarantees identical memory layout. This cast is safe because
109                    // we're only changing the type metadata, not the actual data.
110                    unsafe { &*(self as *const [<$V Layout>] as *const $crate::LayoutAdapter<$V>) }
111                }
112            }
113
114            impl std::ops::Deref for [<$V Layout>] {
115                type Target = dyn $crate::Layout;
116
117                fn deref(&self) -> &Self::Target {
118                    // SAFETY: LayoutAdapter is #[repr(transparent)] over the Layout type,
119                    // which guarantees identical memory layout. This cast is safe because
120                    // we're only changing the type metadata, not the actual data.
121                    unsafe { &*(self as *const [<$V Layout>] as *const $crate::LayoutAdapter<$V>) }
122                }
123            }
124
125            impl $crate::IntoLayout for [<$V Layout>] {
126                fn into_layout(self) -> $crate::LayoutRef {
127                    // SAFETY: LayoutAdapter is #[repr(transparent)] over the Layout type,
128                    // guaranteeing identical memory layout and alignment. The transmute is safe
129                    // because both types have the same size and representation.
130                    std::sync::Arc::new(unsafe { std::mem::transmute::<[<$V Layout>], $crate::LayoutAdapter::<$V>>(self) })
131                }
132            }
133
134            impl From<[<$V Layout>]> for $crate::LayoutRef {
135                fn from(value: [<$V Layout>]) -> $crate::LayoutRef {
136                    use $crate::IntoLayout;
137                    value.into_layout()
138                }
139            }
140
141            impl AsRef<dyn $crate::LayoutEncoding> for [<$V LayoutEncoding>] {
142                fn as_ref(&self) -> &dyn $crate::LayoutEncoding {
143                    // SAFETY: LayoutEncodingAdapter is #[repr(transparent)] over the LayoutEncoding type,
144                    // which guarantees identical memory layout. This cast is safe because
145                    // we're only changing the type metadata, not the actual data.
146                    unsafe { &*(self as *const [<$V LayoutEncoding>] as *const $crate::LayoutEncodingAdapter<$V>) }
147                }
148            }
149
150            impl std::ops::Deref for [<$V LayoutEncoding>] {
151                type Target = dyn $crate::LayoutEncoding;
152
153                fn deref(&self) -> &Self::Target {
154                    // SAFETY: LayoutEncodingAdapter is #[repr(transparent)] over the LayoutEncoding type,
155                    // which guarantees identical memory layout. This cast is safe because
156                    // we're only changing the type metadata, not the actual data.
157                    unsafe { &*(self as *const [<$V LayoutEncoding>] as *const $crate::LayoutEncodingAdapter<$V>) }
158                }
159            }
160        }
161    };
162}