Skip to content
This repository has been archived by the owner on Sep 11, 2023. It is now read-only.

Default values for missing fields during deserialization #27

Open
zesterer opened this issue Aug 10, 2022 · 2 comments
Open

Default values for missing fields during deserialization #27

zesterer opened this issue Aug 10, 2022 · 2 comments

Comments

@zesterer
Copy link

Hello. Is there a sensible way to have EnumMap use default values for each key if their key is not present when deserializing from a human-readable format?

@KamilaBorowska
Copy link
Owner

KamilaBorowska commented Aug 10, 2022

It's possible to manually implement deserialization function that provides a default using serde(deserialize_with) functionality. Hopefully it will help, I may later consider adding functionality to use default values for enum maps to serde_with crate.

use enum_map::{EnumArray, EnumMap};
use serde::de::{Deserializer, MapAccess, Visitor};
use serde::Deserialize;
use std::fmt;
use std::marker::PhantomData;

#[derive(Deserialize, Debug)]
struct DefaultEnumMap(#[serde(deserialize_with = "default_values")] EnumMap<u8, String>);

fn default_values<'de, D, K, V>(deserializer: D) -> Result<EnumMap<K, V>, D::Error>
where
    D: Deserializer<'de>,
    K: Deserialize<'de> + EnumArray<V>,
    V: Deserialize<'de> + Default,
{
    struct EnumMapVisitor<K, V>(PhantomData<(K, V)>);
    impl<'de, K, V> Visitor<'de> for EnumMapVisitor<K, V>
    where
        K: Deserialize<'de> + EnumArray<V>,
        V: Deserialize<'de> + Default,
    {
        type Value = EnumMap<K, V>;
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            write!(formatter, "a map")
        }
        fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<EnumMap<K, V>, M::Error> {
            let mut entries = EnumMap::default();
            while let Some((key, value)) = access.next_entry()? {
                entries[key] = value;
            }
            Ok(entries)
        }
    }
    deserializer.deserialize_map(EnumMapVisitor(PhantomData))
}

fn main() {
    println!(
        "{:?}",
        serde_json::from_str::<DefaultEnumMap>(r#"{"2": "abc", "5": "def"}"#),
    );
}

@zesterer
Copy link
Author

Thanks. I've ended up implementing something similar myself, but I guess there's not really a good way to have this included upstream without breaking the current semantics. Thanks!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants