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}