serde-rs / serde

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

Serialize trait not implemented for nested Map #2694

Closed BTOdell closed 6 months ago

BTOdell commented 7 months ago

Code example:

#[derive(Serialize, Deserialize, Clone)]
pub struct MyJson {
    pub name: String,
    #[serde(skip_serializing_if = "Map::is_empty")]
    #[serde(default)]
    pub args: Map<String, Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub config: Option<Map<String, Map<String, Value>>>,
}

Compile error:

7    | #[derive(Serialize, Deserialize, Clone)]
     |          ^^^^^^^^^ the trait `Serialize` is not implemented for `serde_json::Map<std::string::String, serde_json::Map<std::string::String, serde_json::Value>>`

If I change the config property, the error goes away:

#[derive(Serialize, Deserialize, Clone)]
pub struct MyJson {
    pub name: String,
    #[serde(skip_serializing_if = "Map::is_empty")]
    #[serde(default)]
    pub args: Map<String, Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub config: Option<Map<String, Value>>,  // change nested serde_json::Map<_,_> to a serde_json::Value
}

Not sure how this could be possible since both serde_json::Map and serde_json::Value are both Serialize, so how could combining them in this way trigger a compile error?

BTOdell commented 7 months ago

Just tried changing serde_json::Map to std::collections::HashMap and it compiles fine. So I think there is definitely a bug or missing functionality in serde_json::Map that needs to be fixed.

#[derive(Serialize, Deserialize, Clone)]
pub struct MyJson {
    pub name: String,
    #[serde(skip_serializing_if = "Map::is_empty")]
    #[serde(default)]
    pub args: Map<String, Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub config: Option<HashMap<String, HashMap<String, Value>>>,
}

Or:

#[derive(Serialize, Deserialize, Clone)]
pub struct MyJson {
    pub name: String,
    #[serde(skip_serializing_if = "Map::is_empty")]
    #[serde(default)]
    pub args: Map<String, Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub config: Option<HashMap<String, Map<String, Value>>>,
}

It's the first (outer) Map that is causing the compile errors.

BTOdell commented 7 months ago

I just realized that the serde_json::Map<> type is only implemented for the Map<String, Value> specialization. I think it's confusing that Map has two generic parameters when it can only be used to hold a serde_json::Value as the map's value.

Can the Map type be extended to support any value type instead of just serde_json::Value?