serde-rs / serde

Serialization framework for Rust
https://serde.rs/
Apache License 2.0
9.17k stars 774 forks source link

Flattened maps with numeric keys do not work correctly. #1638

Closed tomusdrw closed 4 years ago

tomusdrw commented 5 years ago
#[derive(serde::Deserialize)]
struct A {
    pub map: std::collections::BTreeMap<u64, String>,
}

#[derive(serde::Deserialize)]
struct B {
    #[serde(flatten)]
    pub map: std::collections::BTreeMap<u64, String>,
}

fn main() {
    // works
    let a: A = serde_json::from_str(r#"{"map": {"1": "a", "2": "b"}}"#).unwrap();
    // fails
    let b: B = serde_json::from_str(r#"{"1": "a", "2": "b"}"#).unwrap();
}

The second call fails with Error("invalid type: string \"1\", expected u64", line: 1, column: 20)'.

Surprisingly (to me) deserializing below struct will fail as well, so it seems it's just enough if the map is nested anywhere in the flattened struct.

#[derive(serde::Deserialize)]
struct C {
    #[serde(flatten)]
    pub map: A,
}
dtolnay commented 4 years ago

The map key conversion from string to number is a serde_json feature so this looks like a special case of https://github.com/serde-rs/serde/issues/1183. I'll close in favor of that issue.

For a workaround it would be reasonable for a crate such as https://github.com/jonasbb/serde_with to provide the conversion from string keys to numeric keys. Please file a feature request over there if it isn't already supported.

#[derive(Deserialize)]
pub struct B {
    #[serde(flatten, with = "???")]
    map: BTreeMap<u64, String>,
}