-
Notifications
You must be signed in to change notification settings - Fork 96
Open
Description
This test case results in Error(Custom("missing field `$value`")
:
#[derive(Debug, Deserialize, PartialEq)]
struct BC {
b: String,
c: String,
}
#[derive(Debug, Deserialize, PartialEq)]
struct D {
d: String,
}
#[derive(Debug, Deserialize, PartialEq)]
struct A {
#[serde(flatten)]
bc: BC,
#[serde(rename = "$value")]
d: D,
}
#[test]
fn flatten_and_value() {
init_logger();
let s = r##"
<A b="1" c="2">
<D d="3"/>
</A>
"##;
let project: A = from_str(s).unwrap();
assert_eq!(
project,
A {
bc: BC {
b: "1".to_string(),
c: "2".to_string(),
},
d: D { d: "3".to_string() }
}
);
}
The reason is this code in serde_derive's deserialize_struct
:
} else if cattrs.has_flatten() {
quote! {
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
}
} else {
let type_name = cattrs.name().deserialize_name();
quote! {
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
}
};
#[serde(flatten)]
causes the generated deserialization code to call deserialize_map
which does not have access to the field names in FIELD
and thus can't spot the $value
and give it special handling.
I'd be keen to fix this but I need some advice about how. I'm brand new to serde.
Options would seem to be:
- Modify serde and serde_derive to pass field names into
deserialize_map
in case it wants to use them (or, to put it another way, don't assume that things are necessarily a map rather than a struct just due to the presence offlatten
- after all, the struct flattening page explicitly lists two reasons you might want to use flatten) - Modify serde_derive to have a new attribute which forces things into
deserialize_struct
rather thandeserialize_map
even ifflatten
is present - Add a new attribute specific to serde-xml-rs which indicates that there is an inner value. For example ``#[serde-xml-rs(has-inner-value)]
. This would result in
MapAccess.inner_value` being true even if we couldn't determine it by the field names because we're in `deserialize_map` rather than `deserialize_struct`. It seems a shame to have this redundancy of course. - Failing all else, just update the documentation to explain this pitfall!
Please let me As well as being new to Serde, I'm pretty new to Rust so it may be that one or more of the above ideas are complete bobbins and/or the syntax is nonsense.
estk, bminixhofer, tobz1000, martinlindhe, ch1nq and 4 more
Metadata
Metadata
Assignees
Labels
No labels