Skip to main content

vortex_layout/plan/physical/
vtable.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::borrow::Cow;
5use std::fmt;
6use std::fmt::Debug;
7use std::ops::Range;
8
9use vortex_array::DeserializeMetadata;
10use vortex_array::SerializeMetadata;
11use vortex_error::VortexResult;
12use vortex_error::vortex_bail;
13use vortex_mask::Mask;
14use vortex_session::registry::Id;
15
16use crate::plan::physical::PlanChildren;
17use crate::plan::physical::pipeline::Chain;
18use crate::plan::physical::pipeline::Compiler;
19use crate::plan::physical::pipeline::Reach;
20use crate::plan::physical::typed::Plan;
21use crate::segments::SegmentId;
22
23/// A unique identifier for a plan operator.
24pub type PlanId = Id;
25
26/// Operator-specific behavior for a typed [`Plan`].
27///
28/// Common fields — dtype, row count, and children — are stored outside the erased operator data.
29/// Implementations own only their operator-specific data, its metadata codec, and a callback for
30/// refreshing cached data after generic child replacement.
31///
32/// Operators describe physical work over a row domain. Their identity and operator-specific data
33/// do not depend on the source layout kind. The common lazy-child storage may nevertheless own a
34/// hidden source-layout reference used for on-demand lowering.
35pub trait PlanVTable: 'static + Clone + Sized + Send + Sync + Debug {
36    /// Operator-specific data, excluding children.
37    ///
38    /// Children belong in [`PlanParts::children`](crate::plan::physical::PlanParts::children) so that
39    /// traversal and rewriting can discover them generically.
40    type PlanData: 'static + Send + Sync + Clone + Debug;
41
42    /// Serialized form of [`PlanData`](Self::PlanData).
43    type Metadata: SerializeMetadata + DeserializeMetadata + Debug;
44
45    /// Returns the globally unique operator ID.
46    fn id(&self) -> PlanId;
47
48    /// Writes operator-specific fields after the plan's standard display summary.
49    fn fmt(plan: &Plan<Self>, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
50        let _ = (plan, formatter);
51        Ok(())
52    }
53
54    /// Returns the serializable metadata for this operator.
55    ///
56    /// Returns `None` when the operator holds state that cannot be serialized.
57    fn metadata(plan: &Plan<Self>) -> Option<Self::Metadata>;
58
59    /// Refreshes cloned operator data after the common child container is replaced.
60    ///
61    /// The plan layer clones [`PlanData`](Self::PlanData), replaces the children externally, and
62    /// invokes this callback. Implementations validate the new children and update any derived
63    /// values in `data`; they do not rebuild the plan itself.
64    fn with_children(
65        plan: &Plan<Self>,
66        children: &PlanChildren,
67        data: &mut Self::PlanData,
68    ) -> VortexResult<()> {
69        let _ = (plan, children, data);
70        Ok(())
71    }
72
73    /// Returns the display name of the child at `index`.
74    fn child_name(plan: &Plan<Self>, index: usize) -> Cow<'_, str> {
75        let _ = plan;
76        Cow::Owned(format!("child[{index}]"))
77    }
78
79    /// Compiles this plan over `rows` of its row domain, restricted to `mask`, into a chain:
80    /// a source and the stages after it, producing the rows `mask` selects in row order, or
81    /// `None` when that is no row. `rows` lies within the plan's row domain and `mask` is as long
82    /// as `rows`.
83    ///
84    /// A plan compiles its children through `compiler` and either adds stages to a child's
85    /// chain or joins several children's chains with a source of its own. Compiling does no IO.
86    fn compile(
87        plan: &Plan<Self>,
88        rows: Range<u64>,
89        mask: &Mask,
90        compiler: &mut Compiler<'_>,
91    ) -> VortexResult<Option<Chain>> {
92        let _ = (rows, mask, compiler);
93        vortex_bail!("Plan {} has no pipeline implementation", plan.vtable().id())
94    }
95
96    /// Visits every segment compiling this plan over `rows` could read, under any mask, with
97    /// the rows of the scanned plan it is read for, so a segment more than one reader reads is
98    /// decoded once. `at` maps this plan's rows to the scanned plan's.
99    ///
100    /// The default visits nothing, so the segments under a plan that does not override it are
101    /// read by each reader alone.
102    fn reach(
103        plan: &Plan<Self>,
104        rows: Range<u64>,
105        at: &Reach,
106        visit: &mut dyn FnMut(SegmentId, Range<u64>),
107    ) -> VortexResult<()> {
108        let _ = (plan, rows, at, visit);
109        Ok(())
110    }
111}