Restore the From / TryFrom proto conversions dropped since 54.1.0 - #24205
Restore the From / TryFrom proto conversions dropped since 54.1.0#24205adriangb wants to merge 7 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Restores standard protobuf From/TryFrom conversions by relocating implementations to crates that satisfy Rust’s orphan rules.
Changes:
- Moves expression, common-type, datasource, format-factory, and physical-column conversions to owning crates.
- Replaces the unsupported slice conversion with
partitioned_files_to_proto. - Adds migration documentation and compile-time API regression tests.
Reviewed changes
Copilot reviewed 26 out of 27 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
docs/source/library-user-guide/upgrading/55.0.0.md |
Documents the slice-conversion migration. |
datafusion/proto/tests/cases/roundtrip_logical_plan.rs |
Uses restored standard conversions. |
datafusion/proto/tests/cases/public_conversions.rs |
Adds compile-time API guards, but misses six restored impls. |
datafusion/proto/tests/cases/mod.rs |
Registers the new tests. |
datafusion/proto/src/physical_plan/to_proto.rs |
Removes encoding shims and re-exports the slice helper. |
datafusion/proto/src/physical_plan/from_proto.rs |
Removes decoding shims and relocated tests. |
datafusion/proto/src/logical_plan/to_proto.rs |
Uses relocated standard conversions. |
datafusion/proto/src/logical_plan/mod.rs |
Updates logical-plan conversion calls. |
datafusion/proto/src/logical_plan/from_proto.rs |
Removes local decoding implementations. |
datafusion/proto/src/logical_plan/file_formats.rs |
Delegates format-option conversions to owning crates. |
datafusion/proto/src/convert.rs |
Documents the now-unused custom traits. |
datafusion/proto/src/common.rs |
Marks the custom conversion macro unused. |
datafusion/proto/Cargo.toml |
Enables expression protobuf support. |
datafusion/proto-models/src/to_proto.rs |
Adds common-type protobuf encoders. |
datafusion/proto-models/src/lib.rs |
Exposes conversion modules. |
datafusion/proto-models/src/from_proto.rs |
Adds common-type protobuf decoders. |
datafusion/proto-models/Cargo.toml |
Adds the common crate dependency. |
datafusion/physical-expr/src/expressions/column.rs |
Restores physical-column conversions. |
datafusion/expr/src/proto.rs |
Adds expression protobuf conversions and tests. |
datafusion/expr/src/lib.rs |
Registers the feature-gated conversion module. |
datafusion/expr/Cargo.toml |
Adds the optional proto feature. |
datafusion/datasource/src/proto.rs |
Adds the slice conversion function and tests. |
datafusion/datasource/src/mod.rs |
Makes the protobuf module public. |
datafusion/datasource-parquet/src/file_format.rs |
Moves Parquet factory encoding. |
datafusion/datasource-json/src/file_format.rs |
Moves JSON factory encoding. |
datafusion/datasource-csv/src/file_format.rs |
Moves CSV factory encoding. |
Cargo.lock |
Records dependency changes. |
Suppressed comments (1)
datafusion/proto/tests/cases/public_conversions.rs:117
- This guard does not cover four restored file-format impls: encoding each of
CsvFormatFactory,JsonFormatFactory, andParquetFormatFactory, plus decodingParquetCdcOptions. Their removal would therefore go undetected despite this test's stated goal of pinning every restored conversion. Please add assertions for all four.
fn file_format_option_conversions_are_std_traits() {
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #24205 +/- ##
==========================================
+ Coverage 81.05% 81.07% +0.01%
==========================================
Files 1107 1109 +2
Lines 381574 381940 +366
Branches 381574 381940 +366
==========================================
+ Hits 309281 309647 +366
+ Misses 54034 53999 -35
- Partials 18259 18294 +35 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
b1c2dbf to
a735f35
Compare
|
Thank you for opening this pull request! Reviewer note: cargo-semver-checks reported the current version number is not SemVer-compatible with the changes in this pull request (compared against the base branch). Details |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 29 changed files in this pull request and generated no new comments.
Suppressed comments (2)
datafusion/proto/tests/cases/public_conversions.rs:90
- This compile-time regression guard omits both restored
MergeIntoClauseKindconversions. Removing either impl would therefore still leave this test suite compiling, despite this file's stated purpose of pinning every restored standard-trait conversion. Add both directions to the guard.
fn window_frame_conversions_are_std_traits() {
datafusion/proto/tests/cases/public_conversions.rs:124
- This guard misses four relocated public impls: encoding each CSV/JSON/Parquet format factory, and decoding
ParquetCdcOptions. Those APIs can regress without failing the test. Please assert their exact signatures alongside the other file-format conversions.
fn file_format_option_conversions_are_std_traits() {
The real `TryFrom` impls for `PartitionedFile`, `FileRange`, `FileGroup` (apache#24006) and for `JsonSink` / `CsvSink` / `ParquetSink` / `FileSinkConfig` (apache#23781) now live next to the types, so the `TryFromProto` copies in `datafusion-proto` were pure delegation. `TryFrom<&[PartitionedFile]> for protobuf::FileGroup` goes away here and comes back in the `datafusion-proto-models` commit, which is the one crate that can express it. The `PartitionedFile` tests move to `datafusion-datasource` alongside the logic they cover; the two that duplicated existing coverage there are dropped. Part of apache#24019. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…datafusion-expr `WindowFrame`, `WindowFrameBound`, `WindowFrameUnits`, `MergeIntoClauseKind` and `NullTreatment` are owned by `datafusion-expr`, so the orphan rule lets their proto conversions live next to the types as standard `From` / `TryFrom` impls — the shape they had in 54.1.0 — instead of the `FromProto` / `TryFromProto` workaround. `datafusion-expr` gains a `proto` feature (optional `datafusion-proto-common` and `datafusion-proto-models` deps), matching `datafusion-datasource`. The error types are unchanged: `FromProtoError` decoding, `ToProtoError` encoding. Part of apache#24019. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…roto-models
`UnnestOptions`, `TableReference`, `StringifiedPlan`, `JoinType`,
`JoinConstraint`, `NullEquality`, `CsvOptions`, `JsonOptions` and the parquet
options types all live in `datafusion-common`, which sits below
`datafusion-proto-models` in the crate graph and so cannot host the impls.
They move onto the local proto type in `datafusion-proto-models` instead — the
arrangement `datafusion-proto-common` already uses for `ScalarValue` and
`Statistics` — and go back to being plain `From` / `TryFrom`, the shape they
had in 54.1.0.
This is also the only crate that can express
`TryFrom<&[PartitionedFile]> for protobuf::FileGroup`. `datafusion-datasource`
cannot: `&T` is `#[fundamental]` but `[T]` is not, so `&[PartitionedFile]`
counts as foreign there. Here the *self* type is local, which is all the orphan
rule needs, and staying generic over the element (`&T: TryInto<protobuf::PartitionedFile>`)
means this crate never has to name `PartitionedFile`, which sits above it.
Callers get the 54.1.0 spelling back verbatim.
New `datafusion_proto_models::{from_proto, to_proto}` modules; the crate gains
a direct `datafusion-common` dependency (already present transitively via
`datafusion-proto-common`).
Part of apache#24019.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rmat crates
`CsvFormatFactory`, `JsonFormatFactory` and `ParquetFormatFactory` are owned by
`datafusion-datasource-{csv,json,parquet}`, so their options-encoding
conversions become plain `From` impls next to the types, behind each crate's
existing `proto` feature.
This is the last `FromProto` / `TryFromProto` impl in the tree: `convert.rs`
and `convert_required_proto!` now have no implementors, clearing the way for
the final cleanup in apache#24019.
Part of apache#24019.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Restores `From<&protobuf::PhysicalColumn> for Column` (and adds the encoding direction, which `Column::try_to_proto` now uses) — the last of the 39 conversions 54.1.0 published. Adds `tests/cases/public_conversions.rs`, which coerces every one of those conversions to a `fn` pointer. `cargo-semver-checks` has no lint for a removed hand-written trait impl, which is why this class of break went unnoticed; a compile-time reference does catch it, and stays quiet when an impl merely moves between crates. Part of apache#24019. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The parquet options conversions validate `writer_version` now, so they are `TryFrom` rather than `From`. Everything else needs no entry: the impls that moved crates still resolve unchanged, because trait impls are global. Part of apache#24019. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
apache#21929 introduced these traits so the `datafusion-proto-models` extraction could land without simultaneously relocating ~39 conversions, and flagged them there as "a known workaround, not the end state". Every one of those conversions now lives in a crate that owns one side of it, as a plain `From` / `TryFrom`, so the traits and `convert_required_proto!` have no implementors and no callers. Neither trait has ever shipped in a release, so this removes them outright rather than deprecating: there is nothing for downstream users to migrate off. Doing it before 55.0.0 keeps the workaround out of the released API entirely. Closes apache#24019. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
a735f35 to
783d5ad
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 28 changed files in this pull request and generated no new comments.
Suppressed comments (2)
datafusion/datasource-parquet/src/file_format.rs:703
- This newly added struct literal is not rustfmt-formatted: its fields are aligned with the literal rather than nested, and several expressions below remain unreflowed. The required
cargo fmt --allcheck will rewrite this whole block; please run it before merging.
protobuf::TableParquetOptions {
global: Some(protobuf::ParquetOptions {
datafusion/proto-models/src/from_proto.rs:128
- This new line is not rustfmt-formatted, so the repository's required
cargo fmt --allcheck will rewrite it. Please format the file before merging.
analyzer_name:analyzer_name.clone()
Which issue does this PR close?
From/TryFromproto conversions dropped since 54.1.0, and retireFromProto/TryFromProto#24019.Rationale for this change
datafusion-proto54.1.0 publishes 39From/TryFromimpls converting between DataFusion types and their protobuf messages. Onmainall of them were replaced by the crate-localFromProto/TryFromPrototraits introduced in #21929, so code written against the released version stops compiling:That was collateral damage from the orphan-rule workaround, not an intended API change.
cargo-semver-checkshas no lint for a removed hand-written trait impl, and thebreaking_changes_detectorworkflow baselines againstapache/mainrather than the last release, so nothing flagged it.What changes are included in this PR?
Each conversion moves to a crate that owns one side of it, and goes back to being a plain
From/TryFrom— the shape 54.1.0 published. Error types are unchanged (FromProtoErrordecoding,ToProtoErrorencoding,DataFusionErrorfor the datasource types).PartitionedFile,FileRange,FileGroup,JsonSink,CsvSink,ParquetSink,FileSinkConfigTryFromProtoshims that delegated to themWindowFrame,WindowFrameBound,WindowFrameUnits,MergeIntoClauseKind,NullTreatmentdatafusion-expr, behind a newprotofeature (optionaldatafusion-proto-common/datafusion-proto-modelsdeps, mirroringdatafusion-datasource)UnnestOptions,TableReference,StringifiedPlan,JoinType,JoinConstraint,NullEquality,CsvOptions,JsonOptions, and the parquet options typesdatafusion-proto-models, on the local proto type — their DataFusion side sits below that crate in the graph, the same arrangementdatafusion-proto-commonalready uses forScalarValue/StatisticsCsvFormatFactory,JsonFormatFactory,ParquetFormatFactorydatafusion-datasource-{csv,json,parquet}, behind each crate's existingprotofeatureColumn<->protobuf::PhysicalColumndatafusion-physical-expr;Column::try_to_proto/try_from_protonow go through it instead of building the message inlineTryFrom<&[PartitionedFile]> for protobuf::FileGroupneeded one extra step.datafusion-datasourcecannot host it —&Tis#[fundamental]but[T]is not, so&[PartitionedFile]counts as foreign there (error[E0117]: slices are always foreign). But indatafusion-proto-modelsthe self type is local, which is all the orphan rule needs, and staying generic over the element avoids namingPartitionedFile, which sits above that crate in the graph:The bound is satisfied by
TryFrom<&PartitionedFile> for protobuf::PartitionedFileindatafusion-datasource, soprotobuf::FileGroup::try_from(&files[..])resolves for callers exactly as it did in 54.1.0 — zero-copy, and no free function.Two items beyond the issue's checklist, both needed to reach zero implementors:
ParquetOptions,TableParquetOptions,ParquetColumnOptions,ParquetCdcOptions) — the issue's table undercountsfile_formats.rsbecause they live in a private module, but trait impls are global, so they were public API too. They return asTryFrom;mainhad already made them fallible, so an exact restore of 54.1.0's infallibleFromisn't available.From<&protobuf::PhysicalColumn> for Column, which the issue's evidence table counts but no work item names.Not restored, and worth calling out:
From<protobuf::dml_node::Type> for WriteOpand its reverse.mainreplaced them withparse_write_op/serialize_write_opbecauseMergeIntocarries a payload aFromimpl cannot express. That is a separate, deliberate change.Finally,
convert.rsandconvert_required_proto!are deleted. #21929 introducedFromProto/TryFromProtoso thedatafusion-proto-modelsextraction could land without relocating ~39 conversions at the same time, and flagged them there as "a known workaround, not the end state", with dropping them listed under Future work. With every conversion moved they have no implementors and no callers. Neither trait has ever shipped in a release, so they are removed outright rather than deprecated — there is nothing for downstream users to migrate off, and doing it now keeps the workaround out of the released API entirely.Are these changes tested?
Yes.
datafusion/proto/tests/cases/public_conversions.rscoerces all 45 proto conversions in the touched crates tofnpointers (the 39 from 54.1.0 plus the ones added onmain). This is the regression guard the issue asks for: it fails to compile when an impl is removed, and stays quiet when one merely moves between crates, which is exactly the casecargo-semver-checkscannot see.datafusion-expranddatafusion-proto-models(window frames, table references, join enums, unnest options, stringified plans).PartitionedFiletests move fromdatafusion-prototodatafusion-datasource, alongside the logic they cover; two that duplicated existing coverage there are dropped.roundtrip_logical_plan,roundtrip_physical_plan) pass unchanged, which is the real wire-format check.main: 22 are byte-identical modulo the trait rename, and the other 9 differ only bySelf::shorthand, error-type aliasing, and rustfmt reflow. No serialization logic changed../dev/rust_lint.sh,cargo machete, and the extended test suite all pass at HEAD. Also checked:datafusion-protowithoutparquet,datafusion-exprwithprotooff and--no-default-features, the format crates withoutproto, andjsonon both proto crates.Are there any user-facing changes?
Yes, and they restore rather than break the released API.
X::try_from(&proto)/proto.try_into()resolve regardless of which crate now hosts the impl — no import changes needed, and no upgrade-guide entry for the moves.TryFromrather than 54.1.0's infallibleFrom. That predates this PR —mainhad already made them fallible — but it is a real 54.1.0 -> 55.0.0 break and was undocumented, so it is now in the 55.0.0 upgrade guide with a migration snippet.FromProto/TryFromProtoandconvert_required_proto!are gone. Not a breaking change: they exist only onmainand appear nowhere in 54.0.0 or 54.1.0.datafusion-exprgains an off-by-defaultprotofeature. Additive.datafusion-proto-modelsgains a directdatafusion-commondependency (already present transitively) and two new public modules.Keeping the
api changelabel for the parquet options fallibility.