Reputation: 4628
I have an enum that is composed of other enums, similar to the following (serde
derives and annotations omitted for brevity):
enum Main {
A(SubA),
B(SubB),
}
enum SubA { X1, X2, X3 }
enum SubB { Y1, Y2, Y3 }
I'd love to be able to use serde
to deserialize a string such as "X1" or "Y3", and automatically get back a Main::A(SubA::X1)
or Main::B(SubB::Y3)
, respectively.
I understand that serde
supports a #[serde(transparent)]
attribute on newtype-style structs, which would do what I like. However, it only seems to work on the struct or enum level, not at the enum-variant level. Is there a way I can automagically get the behavior I'm looking for? I can ensure that there would be no overlap in any of the variant names in any of the contained sub-enums.
Aside from wanting to remain on Rust 2018 stable, I have no other restrictions on my project, and I'm open to any crate suggestions that would help.
Upvotes: 12
Views: 8508
Reputation: 4891
It works pretty much out of the box if you put serde(untagged)
on the outer enum and nothing special on the inner enums:
use serde_derive::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
enum Main {
A(SubA),
B(SubB),
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
enum SubA { X1, X2, X3 }
#[derive(Debug, Deserialize, Serialize, PartialEq)]
enum SubB { Y1, Y2, Y3 }
fn main() {
let x1 = Main::A(SubA::X1);
let y2 = Main::B(SubB::Y2);
assert_eq!(serde_json::to_string(&x1).unwrap(), "\"X1\"");
assert_eq!(serde_json::to_string(&y2).unwrap(), "\"Y2\"");
assert_eq!(serde_json::de::from_str::<Main>("\"X1\"").unwrap(), x1);
assert_eq!(serde_json::de::from_str::<Main>("\"Y2\"").unwrap(), y2);
}
Upvotes: 19