You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/07/30 15:34:51 UTC

(datafusion) 01/01: refactor: mark the ExecutionPlan proto dispatch traits as non-public API (#24001)

This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-24001-3aef16c74084d56b19b7295e89108f46da5ad826
in repository https://gitbox.apache.org/repos/asf/datafusion.git

commit 541caab85a265c104888f1988fe54b08fa022f53
Author: Adrian Garcia Badaracco <17...@users.noreply.github.com>
AuthorDate: Thu Jul 30 10:34:26 2026 -0500

    refactor: mark the ExecutionPlan proto dispatch traits as non-public API (#24001)
    
    ## Which issue does this PR close?
    
    - Part of #23494. Precursor to #23915 (and to the remaining `DataSource`
    / `DataSink` items, #23497 / #23498).
    
    ## Rationale for this change
    
    `ExecutionPlanEncode` / `ExecutionPlanDecode` (added in #23495) are
    dispatch details of the
    `try_to_proto` / `try_from_proto` hooks, not extension points. They are
    defined in
    `datafusion-physical-plan`, implemented only by `ConverterPlanEncoder` /
    `ConverterPlanDecoder`
    in `datafusion-proto`, and plans reach them exclusively through
    `ExecutionPlanEncodeCtx` /
    `ExecutionPlanDecodeCtx` — their own docs already say so:
    
    > Internal dispatch trait backing [`ExecutionPlanEncodeCtx`].
    Implemented by `datafusion-proto`.
    > Plan authors never name this trait.
    
    They are `pub` only because those adapters live in another crate.
    Nothing said that to the tooling,
    so every capability the epic still has to add to the ctx reads as a
    major breaking change. #23915
    hits this first: it needs `decode_plan_with_scalar_subquery_results` so
    `ScalarSubqueryExec` can
    decode its input with the subquery-results container in scope, and
    `cargo-semver-checks` flags the
    required method as `trait_method_added`. The `DataSource` / `DataSink`
    families will want their own
    primitives next.
    
    `#[doc(hidden)]` states what was already true, and makes those additions
    changes to something that
    was never public API — rather than asking each follow-up PR to explain
    away a breakage report.
    
    ## What changes are included in this PR?
    
    Mark `ExecutionPlanEncode` and `ExecutionPlanDecode` `#[doc(hidden)]`,
    and say why in their docs
    and in the module overview. One file, no behavior, wire-format, or
    signature changes.
    
    A sealed-trait supertrait was the first thing I tried. It is worse here:
    sealing across a crate
    boundary needs a `pub` marker anyway, so it does not actually prevent a
    downstream impl — it just
    adds a public item in order to say "this is not public API", plus an
    `impl` line for every
    implementor including test doubles. `#[doc(hidden)]` says the same thing
    by removing API surface
    instead of adding it, and `cargo-semver-checks` honors both identically
    (measured below).
    
    ## Are these changes tested?
    
    The property this PR buys is a `cargo-semver-checks` classification, so
    it is verified with that
    tool directly — v0.49.0, the version CI installs, invoked the way CI
    invokes it:
    
    | baseline | change under test | result |
    |---|---|---|
    | `main` | add a required method to `ExecutionPlanDecode` |
    `trait_method_added` — **major** |
    | this PR | the same required method | 223 checks pass, **no semver
    update required** |
    
    Worth recording, since it drove the shape of this PR: the lint reads
    `public_api_sealed` from the
    **baseline**, so this has to land before the PRs that add methods, not
    alongside them. Also,
    `cargo-semver-checks` does not re-qualify the traits as public API even
    though
    `ExecutionPlanEncodeCtx::new` still names them in a public signature.
    
    Also ran, on the pinned 1.97.0 toolchain: `cargo fmt --all -- --check`,
    `cargo clippy --all-targets
    --all-features` for both crates, `cargo doc` with `-D warnings` (no
    broken intra-doc links from the
    module docs to the now-hidden traits), and the full `datafusion-proto`
    integration suite
    (211 passed).
    
    ## Are there any user-facing changes?
    
    `cargo-semver-checks` will report `trait_now_doc_hidden` on this PR, and
    that is the intended
    content of the change.
    
    Real-world impact is nil: both traits were introduced by #23495, which
    merged after `54.1.0` was
    tagged, so no released version of `datafusion-physical-plan` contains
    them. The load-bearing public
    API — `ExecutionPlan::try_to_proto`, the two ctx types,
    `AsExecutionPlan`, `PhysicalExtensionCodec`,
    `PhysicalProtoConverterExtension` — is untouched, and `datafusion-proto`
    needs no change at all.
    
    Note for contributors on #23494: the expression-side equivalents
    (`PhysicalExprEncode` /
    `PhysicalExprDecode` in `physical-expr-common`) have the same shape and
    the same argument, but
    several test doubles across crates implement them. Left for a follow-up.
    
    Co-authored-by: Claude Opus 5 <no...@anthropic.com>
---
 datafusion/physical-plan/src/proto.rs | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/datafusion/physical-plan/src/proto.rs b/datafusion/physical-plan/src/proto.rs
index 2c6636a392..f84cd67d46 100644
--- a/datafusion/physical-plan/src/proto.rs
+++ b/datafusion/physical-plan/src/proto.rs
@@ -33,7 +33,8 @@
 //! * [`ExecutionPlanEncode`] / [`ExecutionPlanDecode`] — internal dispatch
 //!   traits, *defined* here but *implemented* in `datafusion-proto`, that the
 //!   context types delegate to. This is the dependency inversion that keeps the
-//!   proto types flowing in one direction only.
+//!   proto types flowing in one direction only. They are `#[doc(hidden)]`: not
+//!   public API, `pub` only because their implementors live in another crate.
 //!
 //! `datafusion-physical-plan` depends on the pure prost types in
 //! `datafusion-proto-models` (feature `proto`), never on `datafusion-proto`.
@@ -73,6 +74,11 @@ use crate::ExecutionPlan;
 ///
 /// Implemented by `datafusion-proto`. Plan authors never name this trait; they
 /// call methods on [`ExecutionPlanEncodeCtx`] instead.
+///
+/// **Not public API.** `pub` only because the implementors live in another
+/// crate; `#[doc(hidden)]` records that, so encoding primitives can be added
+/// here as the serialization hooks grow without breaking downstream code.
+#[doc(hidden)]
 pub trait ExecutionPlanEncode {
     /// Serialize a child execution plan (recursing through the central
     /// serializer, so the child's own `try_to_proto` hook is honored).
@@ -98,6 +104,11 @@ pub trait ExecutionPlanEncode {
 ///
 /// Implemented by `datafusion-proto`. Plan authors never name this trait; they
 /// call methods on [`ExecutionPlanDecodeCtx`] instead.
+///
+/// **Not public API.** `pub` only because the implementors live in another
+/// crate; `#[doc(hidden)]` records that, so decoding primitives can be added
+/// here as the serialization hooks grow without breaking downstream code.
+#[doc(hidden)]
 pub trait ExecutionPlanDecode {
     /// Deserialize a child execution plan (recursing through the central
     /// deserializer, so the child's own `try_from_proto` is honored).


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org