Semaphor
Semaphor

Reputation: 57

Deserialize map with empty objects as values

I have json documents, that may contain objects which have keys that refer to empty objects, like this

{
  "mylist": {
    "foo": {},
    "bar": {}
  }
}

I would like to deserialize them to a Vec of Strings (and serialize it back to the format above later)

pub struct MyStruct {
  #[serde(skip_serializing_if = "Option::is_none")]
  pub my_list: Option<Vec<String>>; // should contain "foo", "bar"
}

How can I do that with serde?

Upvotes: 2

Views: 1190

Answers (1)

Netwave
Netwave

Reputation: 42746

You need to write your own deserializing method, and use deserialize_with or implement it directly for your type:

use serde::Deserialize; // 1.0.127
use serde::Deserializer;
use serde_json;
use std::collections::HashMap; // 1.0.66

#[derive(Deserialize, Debug)]
pub struct MyStruct {
    #[serde(deserialize_with = "deserialize_as_vec", alias = "mylist")]
    pub my_list: Vec<String>,
}

#[derive(Deserialize)]
struct DesHelper {}

fn deserialize_as_vec<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where
    D: Deserializer<'de>,
{
    let data: HashMap<String, DesHelper> = HashMap::<String, DesHelper>::deserialize(deserializer)?;
    Ok(data.keys().cloned().collect())
}

fn main() {
    let example = r#"
{
  "mylist": {
    "foo": {},
    "bar": {}
  }
}"#;

    let deserialized: MyStruct = serde_json::from_str(&example).unwrap();
    println!("{:?}", &deserialized);
}

Results:

MyStruct { my_list: ["foo", "bar"] }

Playground

Notice the use of the helper struct for the empty parts of them. Code is pretty straight forward, you basically deserialize a map and then just take the keys that is what you need.

Upvotes: 3

Related Questions