Skip to main content

vortex_layout/
encoding.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::any::Any;
5use std::fmt::Debug;
6use std::fmt::Display;
7use std::fmt::Formatter;
8
9use arcref::ArcRef;
10use vortex_array::DeserializeMetadata;
11use vortex_array::dtype::DType;
12use vortex_error::VortexExpect;
13use vortex_error::VortexResult;
14use vortex_error::vortex_panic;
15use vortex_session::registry::Id;
16
17use crate::IntoLayout;
18use crate::LayoutBuildContext;
19use crate::LayoutChildren;
20use crate::LayoutRef;
21use crate::VTable;
22use crate::segments::SegmentId;
23
24/// A unique identifier for a layout encoding.
25pub type LayoutEncodingId = Id;
26/// Shared reference to a registered layout encoding.
27pub type LayoutEncodingRef = ArcRef<dyn LayoutEncoding>;
28
29/// Object-safe layout encoding registered in a [`LayoutSession`](crate::session::LayoutSession).
30///
31/// Encoding instances deserialize serialized layout metadata into concrete [`LayoutRef`] nodes.
32/// New in-tree encodings usually implement [`VTable`] and use [`LayoutEncodingAdapter`], while
33/// foreign encodings can provide an object-safe implementation directly.
34pub trait LayoutEncoding: 'static + Send + Sync + Debug + private::Sealed {
35    /// Returns this encoding as [`Any`] for downcasting.
36    fn as_any(&self) -> &dyn Any;
37
38    /// Returns the globally unique encoding id.
39    fn id(&self) -> LayoutEncodingId;
40
41    /// Build a layout from serialized metadata, segment ids, and children.
42    ///
43    /// Implementations must use `build_ctx` for session-scoped plugin resolution instead of global
44    /// registries.
45    fn build(
46        &self,
47        dtype: &DType,
48        row_count: u64,
49        metadata: &[u8],
50        segment_ids: Vec<SegmentId>,
51        children: &dyn LayoutChildren,
52        build_ctx: &LayoutBuildContext<'_>,
53    ) -> VortexResult<LayoutRef>;
54}
55
56/// Object-safe adapter from a typed layout [`VTable`] to [`LayoutEncoding`].
57#[repr(transparent)]
58pub struct LayoutEncodingAdapter<V: VTable>(V::Encoding);
59
60impl<V: VTable> LayoutEncoding for LayoutEncodingAdapter<V> {
61    fn as_any(&self) -> &dyn Any {
62        self
63    }
64
65    fn id(&self) -> LayoutEncodingId {
66        V::id(&self.0)
67    }
68
69    fn build(
70        &self,
71        dtype: &DType,
72        row_count: u64,
73        metadata: &[u8],
74        segment_ids: Vec<SegmentId>,
75        children: &dyn LayoutChildren,
76        build_ctx: &LayoutBuildContext<'_>,
77    ) -> VortexResult<LayoutRef> {
78        let metadata = <V::Metadata as DeserializeMetadata>::deserialize(metadata)?;
79        let layout = V::build(
80            &self.0,
81            dtype,
82            row_count,
83            &metadata,
84            segment_ids,
85            children,
86            build_ctx,
87        )?;
88
89        // Validate that the builder function returned the expected values.
90        if layout.row_count() != row_count {
91            vortex_panic!(
92                "Layout row count mismatch: {} != {}",
93                layout.row_count(),
94                row_count
95            );
96        }
97        if layout.dtype() != dtype {
98            vortex_panic!("Layout dtype mismatch: {} != {}", layout.dtype(), dtype);
99        }
100
101        Ok(layout.into_layout())
102    }
103}
104
105impl<V: VTable> Debug for LayoutEncodingAdapter<V> {
106    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
107        f.debug_struct("LayoutEncoding")
108            .field("id", &self.id())
109            .finish()
110    }
111}
112
113impl Display for dyn LayoutEncoding + '_ {
114    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
115        write!(f, "{}", self.id())
116    }
117}
118
119impl PartialEq for dyn LayoutEncoding + '_ {
120    fn eq(&self, other: &Self) -> bool {
121        self.id() == other.id()
122    }
123}
124
125impl Eq for dyn LayoutEncoding + '_ {}
126
127impl dyn LayoutEncoding + '_ {
128    pub fn is<V: VTable>(&self) -> bool {
129        self.as_opt::<V>().is_some()
130    }
131
132    pub fn as_<V: VTable>(&self) -> &V::Encoding {
133        self.as_opt::<V>()
134            .vortex_expect("LayoutEncoding is not of the expected type")
135    }
136
137    pub fn as_opt<V: VTable>(&self) -> Option<&V::Encoding> {
138        self.as_any()
139            .downcast_ref::<LayoutEncodingAdapter<V>>()
140            .map(|e| &e.0)
141    }
142}
143
144mod private {
145    use super::*;
146    use crate::layouts::foreign::ForeignLayoutEncoding;
147
148    pub trait Sealed {}
149
150    impl<V: VTable> Sealed for LayoutEncodingAdapter<V> {}
151    impl Sealed for ForeignLayoutEncoding {}
152}