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_session::VortexSession;
15use vortex_session::registry::ReadContext;
16
17use crate::LayoutId;
18use crate::LayoutRef;
19use crate::VTable;
20use crate::children::LayoutChildren;
21use crate::segments::SegmentId;
22
23/// Backwards-compatible name for a layout ID.
24pub type LayoutEncodingId = LayoutId;
25/// Shared reference to a registered layout-vtable plugin.
26pub type LayoutVTableRef = ArcRef<dyn LayoutVTablePlugin>;
27/// Backwards-compatible name for a layout-vtable reference.
28pub type LayoutEncodingRef = LayoutVTableRef;
29
30/// Common fields available while deserializing layout-specific data.
31pub struct LayoutDeserializeArgs<'a> {
32    /// Session used to resolve plugin-owned metadata.
33    pub session: &'a VortexSession,
34    /// Array read context referenced by serialized array metadata.
35    pub array_read_ctx: &'a ReadContext,
36    /// Logical dtype of this layout.
37    pub dtype: &'a DType,
38    /// Number of rows in this layout.
39    pub row_count: u64,
40    /// Directly referenced segments.
41    pub segment_ids: Vec<SegmentId>,
42    /// Lazy child access.
43    pub children: &'a dyn LayoutChildren,
44}
45
46/// Context shared while recursively deserializing layouts.
47pub struct LayoutBuildContext<'a> {
48    /// Session used to resolve plugin-owned metadata.
49    pub session: &'a VortexSession,
50    /// Array read context referenced by serialized array metadata.
51    pub array_read_ctx: &'a ReadContext,
52}
53
54/// Object-safe plugin registered for a layout ID.
55pub trait LayoutVTablePlugin: 'static + Send + Sync + Debug {
56    /// Returns this plugin as [`Any`].
57    fn as_any(&self) -> &dyn Any;
58    /// Returns the globally unique layout ID.
59    fn id(&self) -> LayoutEncodingId;
60    /// Deserializes a layout node.
61    fn build(
62        &self,
63        dtype: &DType,
64        row_count: u64,
65        metadata: &[u8],
66        segment_ids: Vec<SegmentId>,
67        children: &dyn LayoutChildren,
68        build_ctx: &LayoutBuildContext<'_>,
69    ) -> VortexResult<LayoutRef>;
70
71    /// Returns `true` if this layout is indivisible: its readers never register natural split
72    /// boundaries strictly inside their row range (see [`VTable::is_indivisible`]).
73    fn is_indivisible(&self) -> bool {
74        false
75    }
76}
77
78/// Backwards-compatible name for the object-safe layout-vtable plugin.
79pub use LayoutVTablePlugin as LayoutEncoding;
80
81impl<V: VTable> LayoutVTablePlugin for V {
82    fn as_any(&self) -> &dyn Any {
83        self
84    }
85
86    fn id(&self) -> LayoutEncodingId {
87        VTable::id(self)
88    }
89
90    fn build(
91        &self,
92        dtype: &DType,
93        row_count: u64,
94        metadata: &[u8],
95        segment_ids: Vec<SegmentId>,
96        children: &dyn LayoutChildren,
97        build_ctx: &LayoutBuildContext<'_>,
98    ) -> VortexResult<LayoutRef> {
99        let metadata = <V::Metadata as DeserializeMetadata>::deserialize(metadata)?;
100        Ok(V::build(
101            self,
102            dtype,
103            row_count,
104            &metadata,
105            segment_ids,
106            children,
107            build_ctx,
108        )?
109        .into_layout())
110    }
111
112    fn is_indivisible(&self) -> bool {
113        VTable::is_indivisible(self)
114    }
115}
116
117impl Display for dyn LayoutVTablePlugin + '_ {
118    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
119        write!(f, "{}", self.id())
120    }
121}
122
123impl PartialEq for dyn LayoutVTablePlugin + '_ {
124    fn eq(&self, other: &Self) -> bool {
125        self.id() == other.id()
126    }
127}
128
129impl Eq for dyn LayoutVTablePlugin + '_ {}
130
131impl dyn LayoutVTablePlugin + '_ {
132    /// Returns whether this plugin is vtable `V`.
133    pub fn is<V: VTable>(&self) -> bool {
134        self.as_opt::<V>().is_some()
135    }
136
137    /// Downcasts this plugin to vtable `V`.
138    pub fn as_<V: VTable>(&self) -> &V {
139        self.as_opt::<V>()
140            .vortex_expect("layout encoding type mismatch")
141    }
142
143    /// Attempts to downcast this plugin to vtable `V`.
144    pub fn as_opt<V: VTable>(&self) -> Option<&V> {
145        self.as_any().downcast_ref()
146    }
147}