1 unstable release
Uses new Rust 2024
| new 0.1.0 | Feb 22, 2026 |
|---|
#534 in Procedural macros
12KB
121 lines
nested-deserialize
A very special-case implementation of serde::Deserialize for untagged nested enums (also known as merged enums or enum unions).
It applies to the following case:
- "Outer" enum is untagged
- Outer enum has 1-length tuple variants
- ..of which the value is an enum
- which should not have colliding variant names with its "sibling enums" used in other variants of the outer enum (also known as the term non-overlapping)
- which must implement
serde::Deserialize- specifically as an externally tagged enum
- and
strum::VariantNames- where the renaming rules (if any) must be in sync with serde
It effectively achieves the same as copy-pasting the variants of each inner enum into an outer enum (or using a macro to do this), and then implementing TryFrom for the inner enums.
Example
use nested_deserialize::NestedDeserialize;
use strum::VariantNames;
#[derive(Deserialize, VariantNames, Debug)] // `VariantNames` required, subject to change
enum Physics { // "Inner" enum
Velocity { m_s: f64 },
Acceleration { m_s2: f64 },
}
#[derive(Deserialize, VariantNames, Debug)]
enum Chemistry { // "Inner" enum
MolarMass { g_mol: f64 },
PhValue { ph: f64 },
}
#[derive(NestedDeserialize, Debug)] // This crate provides `NestedDeserialize`
enum ScienceData { // "Outer" enum
Phys(Physics),
Chem(Chemistry),
}
Differences with other solutions
#[serde(untagged)]
#[serde(untagged)]tries to parse as each variant in ordernested-deserializedelegates to variants based on the tag (can only support enums)#[serde(untagged)]discards any errors from parsing as the inner variantsnested-deserializeprovides specialized errors for the following:- unknown variant (tag)
- invalid tagged enum shape
- the error from the variant, if a valid variant was specified, but could not be deserialized into
deserialize_untagged_verbose_error
deserialize_untagged_verbose_errortries to parse as each variant in order (like#[serde(untagged)])nested-deserializedelegates to variants based on the tag (can only support enums)deserialize_untagged_verbose_errorreturns errors from all variants it tried- which is good for debugging
- ..but most likely you already knew which variant you were trying to use
nested-deserializeprovides the error from trying to deserialize as the specified variant- or provides a list of valid variants if none matched
- or provides a generic error message in case of an invalid type
serde-untagged
serde-untaggedis not a proc macro- requires writing boilerplate
- ultimate control
nested-deserializeis a proc macro- apply it to an enum and done
- may not satisfy complicated use-cases
AI usage disclosure
I vibecoded this, it's about 150 lines of code (pretty simple), and it seems to work for the described usecase. I plan to rewrite parts if needed, by hand, once I fully understand how proc macros work.
If you're interested in this crate/need this functionality, and willing to spend some time helping me with polishing it, please reach out to me.
To-Do / Wishlist
- remove dependency on
strum - support adjacently tagged enums (the more popular type)
- recursive nesting
Dependencies
~130–520KB
~12K SLoC