Conversation
serde's derive only accepts `with`/`serialize_with`/`deserialize_with` on the variant itself for newtype variants; the same annotation on the variant's single field makes the derive require `Deserialize` for the inner type, which is exactly what the annotation was supposed to replace. Since `serde_as` refused the attribute on a variant, there was no way to spell the substitution for that shape at all. Accept `serde_as` on a newtype variant, process it as if it were written on the variant's single field, and emit the generated `serde` attribute on the variant. All other variant shapes keep rejecting it, with a message pointing at the field, since placing it on the field works there. `default` and `schemars(with = ...)` are not emitted for a variant: serde and schemars have no variant-level counterpart for either. Fixes jonasbb#975 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw3Y3FfAVjRyaAhpCb1BVY
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1006 +/- ##
==========================================
+ Coverage 68.83% 68.89% +0.06%
==========================================
Files 38 38
Lines 9705 9762 +57
==========================================
+ Hits 6680 6726 +46
- Misses 3025 3036 +11 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
For a newtype variant of an adjacently tagged enum, serde's derive only accepts
with/serialize_with/deserialize_withon the variant. Putting the same annotation on thevariant's single field makes the derive require
Deserializefor the inner type — which is thevery thing the annotation was supposed to substitute. Since
serde_asrejected the attribute on avariant outright, there was no way to spell the substitution for that shape at all.
Reproduction against
ea5dfdc(Inneronly implementsDisplay/FromStr, neverDeserialize):Moving it to the documented place, onto the field, does not compile either:
The only thing that works today is writing serde's own annotation by hand:
#[serde(with = "serde_with::As::<DisplayFromStr>")]on the variant.The change
serde_ason a newtype variant is now accepted. The attribute is processed as if it had beenwritten on the variant's single field — so every existing check still runs, including the conflict
check against serde's own
with/serialize_with/deserialize_with— and the generatedserdeattribute is then emitted on the variant, which is where serde wants it. That is the code site you
pointed at in the issue.
Every other variant shape keeps rejecting the attribute, now with a message that says to put it on
the field. Writing
serde_ason both a variant and its field is rejected as ambiguous.#[apply]opts out of the new variant handling, so its behaviour is unchanged.
This also covers the original shape from #499, which is why that compile-fail case moves over to
tests/json.rsas a success case; the remaining error paths get a new compile-fail test.Judgement calls, both worth disagreeing with
Newtype variants only. serde accepts
withon struct and tuple variants too, but for those theattribute already works on the field, and you said in the issue that you left
serde_asoffvariants on purpose. Narrowing to the shape that is actually broken keeps this a bug fix rather
than the feature you deliberately omitted. If you would rather have it on all variant shapes for
symmetry with
serde(with = ...), that is a small follow-up.schemarsannotations are not emitted for a variant. I could not find a variant-levelschemars(with = ...)and did not want to emit something I had no way to test, so a newtypevariant annotated with
serde_asgets a schema for the original inner type, not the substitutedone. That is a real gap, not an oversight — if schemars does support it, say so and I will add it.
serde(default)is suppressed for the same reason: serde has no variant-leveldefault.Verification
On macOS arm64, stable cargo 1.95:
cargo test --no-fail-fast,cargo test --all-features --no-fail-fast, andcargo test --no-default-features --no-fail-fastall pass.cargo fmt --all -- --checkclean.--no-default-features, default,--all-features, eachwith
--all-targets) are clean.CI will need to confirm Linux, beta/nightly, MSRV, and the
thumbv7emno_stdchecks — I have notrun those.
Fixes #975