-
Notifications
You must be signed in to change notification settings - Fork 129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C-like enum nested inside of an internally tagged enum fails to deserialize #449
Comments
Thank you for the detailed report @GoldsteinE :) I've expanded it a bit to cover all enum cases: use serde_derive::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
enum InnerEnum {
UnitVariant,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
struct Container {
field: InnerEnum,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
enum OuterEnum {
Variant(Container),
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "tag")]
enum OuterEnumInternal {
Variant(Container),
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "tag", content = "c")]
enum OuterEnumAdjacent {
Variant(Container),
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(untagged)]
enum OuterEnumUntagged {
Variant(Container),
}
#[test]
fn test_enum_in_enum_roundtrip() {
let outer = OuterEnum::Variant(Container { field: InnerEnum::UnitVariant });
let ron = ron::to_string(&outer).unwrap();
assert_eq!(ron, "Variant((field:UnitVariant))");
let de = ron::from_str::<OuterEnum>(&ron);
assert_eq!(de, Ok(outer));
}
#[test]
fn test_enum_in_internally_tagged_roundtrip() {
let outer = OuterEnumInternal::Variant(Container { field: InnerEnum::UnitVariant });
let ron = ron::to_string(&outer).unwrap();
assert_eq!(ron, "(tag:\"Variant\",field:UnitVariant)");
// Wrong JSONy RON would correctly deserialise here
assert_eq!(ron::from_str::<OuterEnumInternal>("(tag:\"Variant\",field:\"UnitVariant\")").as_ref(), Ok(&outer));
let de = ron::from_str::<OuterEnumInternal>(&ron);
// FAILS
assert_eq!(de, Ok(outer));
}
#[test]
fn test_enum_in_adjacently_tagged_roundtrip() {
let outer = OuterEnumAdjacent::Variant(Container { field: InnerEnum::UnitVariant });
let ron = ron::to_string(&outer).unwrap();
assert_eq!(ron, "(tag:\"Variant\",c:(field:UnitVariant))");
let de = ron::from_str::<OuterEnumAdjacent>(&ron);
assert_eq!(de, Ok(outer));
}
#[test]
fn test_enum_in_untagged_roundtrip() {
let outer = OuterEnumUntagged::Variant(Container { field: InnerEnum::UnitVariant });
let ron = ron::to_string(&outer).unwrap();
assert_eq!(ron, "(field:UnitVariant)");
// Wrong JSONy RON would correctly deserialise here
assert_eq!(ron::from_str::<OuterEnumUntagged>("(field:\"UnitVariant\")").as_ref(), Ok(&outer));
let de = ron::from_str::<OuterEnumUntagged>(&ron);
// FAILS
assert_eq!(de, Ok(outer));
} Normal enums and adjacently tagged enums work here, but untagged enums and internally tagged enums fail. In both cases, the problem is that |
I think that “RON does not support untagged and internally tagged enums (and also flattening)” should be documented in some visible place, because it’s features that are normally expected from a serde format, and people use enums a lot in “Rusty” code. It’s especially important given that README says:
and also
which is really misleading, given that The (only?) way to get the information about RONs limitations now is to read through the issues, which the user isn’t supposed to do IMO. I think a “Limitations / known bugs” section in the README and/or the docs.rs/ron page would be really helpful to the new users. The other thing that I think is worth exploring is a way to make the error message more useful. Currently it doesn’t even point to the correct span, so the issue takes some effort to minimize and debug. |
I think I would disagree with that on a technicality though I see why it seems like it from a user perspective. We do support the serde full data model, serde's attributes are implemented outside of that which makes them so difficult to support in any format that does not behave like JSON. In fact, RON does support enums while JSON does not and it means that to support these attributes we would have to transform everything inside I do agree that adding a limitations section would be useful to point this out to new users.
The problem is that serde attributes are entirely independent of the serde formats and not something we have any control over. They are implemented in serde with the assumption that dataformats work similar to JSON with no ability for the formats to hook into. So unfortunately the entire enum tagging happens outside of RON (effectively inside the generated The same holds for the span. The way internally tagged enums work is that serde uses |
I've opened #450 - does that limitations section look good to you? |
I think it certainly helps, thanks. |
I've found a way untagged and internally tagged enums could be supported at minimal code cost but with some heavy sighs -> #451 #403 is also still hanging around as an idea for how struct flattening could be supported. Unfortunately it is again a case where serde just imposes JSON semantics and thus requires some uncomfortable hacks. What are your thoughts? |
Trying to roundtrip this type Rust-RON-Rust:
gives the following RON:
which produces the following error when trying to deserialize it:
(playground-ish)
Some notes:
ron::Value
reveals that the variant of theInnerEnum
is lost and replaced withUnit
.Full repro code duplicated here for resillience
Possibly related to #217, but doesn’t use neither untagged nor externally tagged enums.
The text was updated successfully, but these errors were encountered: