Serde: Deserialize an array into a HashMap

Created on 18 May 2017  路  2Comments  路  Source: serde-rs/serde

From IRC:

\ is it possible in serde/json to deserialize JSON that is expecting a Vector into a Hashmap with a key that is present in the same JSON struct
\ https://pastebin.com/JrssZRkW

support

Most helpful comment

Here is one possible approach:

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

use std::collections::HashMap;

#[derive(Debug, Serialize, Deserialize)]
pub struct ItemsWrapper {
    #[serde(with = "items")]
    pub items: HashMap<i64, Items>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Items {
    // This is the HashMap key.
    id: i64,
    info: String,
}

mod items {
    use super::Items;

    use std::collections::HashMap;

    use serde::ser::Serializer;
    use serde::de::{Deserialize, Deserializer};

    pub fn serialize<S>(map: &HashMap<i64, Items>, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        serializer.collect_seq(map.values())
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<HashMap<i64, Items>, D::Error>
        where D: Deserializer<'de>
    {
        let mut map = HashMap::new();
        for item in Vec::<Items>::deserialize(deserializer)? {
            map.insert(item.id, item);
        }
        Ok(map)
    }
}

fn main() {
    let j = r#" {
                  "items": [
                    {
                      "id": 3,
                      "info": "three"
                    },
                    {
                      "id": 2,
                      "info": "two"
                    }
                  ]
                } "#;

    println!("{:#?}", serde_json::from_str::<ItemsWrapper>(j).unwrap());
}

All 2 comments

Here is one possible approach:

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

use std::collections::HashMap;

#[derive(Debug, Serialize, Deserialize)]
pub struct ItemsWrapper {
    #[serde(with = "items")]
    pub items: HashMap<i64, Items>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Items {
    // This is the HashMap key.
    id: i64,
    info: String,
}

mod items {
    use super::Items;

    use std::collections::HashMap;

    use serde::ser::Serializer;
    use serde::de::{Deserialize, Deserializer};

    pub fn serialize<S>(map: &HashMap<i64, Items>, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        serializer.collect_seq(map.values())
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<HashMap<i64, Items>, D::Error>
        where D: Deserializer<'de>
    {
        let mut map = HashMap::new();
        for item in Vec::<Items>::deserialize(deserializer)? {
            map.insert(item.id, item);
        }
        Ok(map)
    }
}

fn main() {
    let j = r#" {
                  "items": [
                    {
                      "id": 3,
                      "info": "three"
                    },
                    {
                      "id": 2,
                      "info": "two"
                    }
                  ]
                } "#;

    println!("{:#?}", serde_json::from_str::<ItemsWrapper>(j).unwrap());
}

Shouldn't this be more performant:

pub fn deserialize<'de, D>(deserializer: D) -> Result<HashMap<i64, Items>, D::Error>
where
    D: Deserializer<'de>,
{
    struct ItemsVisitor;

    impl<'de> Visitor<'de> for ItemsVisitor {
        type Value = HashMap<i64, Items>;

        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
            formatter.write_str("a sequence of items")
        }

        fn visit_seq<V>(self, mut seq: V) -> Result<HashMap<i64, Items>, V::Error>
        where
            V: SeqAccess<'de>,
        {
            let mut map = HashMap::with_capacity(seq.size_hint().unwrap_or(0));

            while let Some(item) = seq.next_element::<Items>()? {
                map.insert(item.id, item);
            }

            Ok(map)
        }
    }

    deserializer.deserialize_seq(ItemsVisitor)
}

? My gut feeling tells me it should because this does not allocate a temporary Vec. But cargo bench reports that the difference is negligible (when deserializing arrays of >500 elements), what am I missing?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dtolnay picture dtolnay  路  4Comments

dtolnay picture dtolnay  路  3Comments

Yamakaky picture Yamakaky  路  3Comments

tikue picture tikue  路  4Comments

swfsql picture swfsql  路  3Comments