serde
serde copied to clipboard
Added #[serde(case_insensitive)] container attribute for case-insensitive identifier deserialization
Added an attritube that enables case-insensitive container field/variant identifier deserialization.
A similar attribute been requested in #586, which was closed because case-insensitive parsing was provided by the serde-aux crate. The case insensitive implementation there however seems to first parse the data into a map, convert all keys into lowercase and then deserialize the map into the target type. This is definitely slower than having the code generated by derive compare the field names using case-insensitive comparison. The serde_aux implementation also depends on serde_json::Value and might not work for other data formats.
This PR uses eq_ignore_ascii_case() for case-insensitive comparison, which limits it to ASCII characters. This should be sufficient for most use cases, and the standard library currently doesn't have a case insensitive comparsion function that supports any characters.
Also added tests test_case_insensitive_struct, test_case_insensitive_enum and test_case_insensitive_bytes.
Found a small bug, deriving Deserialize on an empty struct with case_insensitive attribute causes the following error:
expected expression, found keyword `else`
expected expression
main.rs(5, 10): Error originated from macro here
proc-macro derive produced unparseable tokens
This doesn't work on flattened structs, need to investigate it further.
Does this allow enum variants to be case insensitive? Here, I want to be able to deserialize NetworkSourceDeleted
or NETWORKSOURCEDELETED
values as well.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum State {
#[serde(rename = "provisioning")]
Provisioning,
#[serde(rename = "deprovisioning")]
Deprovisioning,
#[serde(rename = "succeeded")]
Succeeded,
#[serde(rename = "failed")]
Failed,
#[serde(rename = "networkSourceDeleted")]
NetworkSourceDeleted,
}
You can mark the whole enum as case insensitive, then all variant names would be case insensitive. The attribute won't work on a single variant though.
It works now on flattened structs. However, you need to add the #[serde(case_insensitive)] attribute on both the parent struct and the flattened struct. If the attribute is only on the parent struct, the parent struct's fields are case insensitive and the flattened struct's fields case sensitive. If the attribute is not on the parent struct, everything is case sensitive regardless of the flattened struct's attributes.
Also, there is quite a lot of duplicate code between CaseInsensitiveFlatStructAccess
and FlatStructAccess
and between CaseInsensitiveFlatMapDeserializer
and FlatMapDeserializer
, not sure if this can be improved.
Looks like the build also now fails on older Rust versions without the eq_ignore_ascii_case function. Previously the function was used only in the code the derive generated, and the derive already required Rust 1.31 or newer, so it wasn't a problem. Now it's also used in the case insensitive flat map deserializer which is part of the main crate even without derives enabled. Not sure how this should be solved.
Any progress?
is this being released?
@dtolnay, merging this would really help Azure SDK for Rust. What can I do to help this along?
@dtolnay If docs are holding this back, I can make a PR for documenting this in https://github.com/serde-rs/serde-rs.github.io/blob/master/_src/container-attrs.md
Looking for comments on #2161 which is an alternative solution that is more generic over the problem
I came here looking for case-insensitive enum deserialization. What's the state of this PR? I don't understand if it's been superseded (and should be closed), or if it's still to be merged (what's keeping it?).
Thanks
Almost 2024 💀