serde icon indicating copy to clipboard operation
serde copied to clipboard

Added #[serde(case_insensitive)] container attribute for case-insensitive identifier deserialization

Open lasa01 opened this issue 3 years ago • 12 comments

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.

lasa01 avatar Oct 06 '20 19:10 lasa01

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

lasa01 avatar Oct 07 '20 13:10 lasa01

This doesn't work on flattened structs, need to investigate it further.

lasa01 avatar Oct 23 '20 07:10 lasa01

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,
    }

ctaggart avatar Jan 13 '21 07:01 ctaggart

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.

lasa01 avatar Jan 13 '21 14:01 lasa01

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.

lasa01 avatar Jan 22 '21 17:01 lasa01

Any progress?

sagudev avatar Apr 04 '21 11:04 sagudev

is this being released?

avnerbarr avatar May 04 '21 14:05 avnerbarr

@dtolnay, merging this would really help Azure SDK for Rust. What can I do to help this along?

cataggar avatar Oct 12 '21 22:10 cataggar

@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

avitex avatar Dec 27 '21 12:12 avitex

Looking for comments on #2161 which is an alternative solution that is more generic over the problem

avitex avatar Jan 23 '22 05:01 avitex

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

albx79 avatar Oct 04 '22 09:10 albx79

Almost 2024 💀

erikjara avatar Dec 18 '23 02:12 erikjara