openconfiguration 1.7.0

OpenConfiguration (OC) is a modular, efficient and flexible approach for the uni-directional exchange of visual e-commerce configurations.
Documentation
use std::collections::HashMap;
use std::{fmt, hash::Hash, marker::PhantomData};

use serde::{
    de::{MapAccess, Visitor},
    Deserialize, Deserializer,
};

pub fn deserialize_optional_map_without_null_values<'de, D, K, V>(
    deserializer: D,
) -> Result<Option<HashMap<K, V>>, D::Error>
where
    D: Deserializer<'de>,
    K: Deserialize<'de> + Hash + Eq,
    V: Deserialize<'de>,
{
    deserializer.deserialize_option(OptionSkipNullValuesMapVisitor {
        marker: PhantomData,
    })
}

pub fn deserialize_map_without_null_values<'de, D, K, V>(
    deserializer: D,
) -> Result<HashMap<K, V>, D::Error>
where
    D: Deserializer<'de>,
    K: Deserialize<'de> + Hash + Eq,
    V: Deserialize<'de>,
{
    deserializer.deserialize_map(SkipNullValuesMapVisitor {
        marker: PhantomData,
    })
}

struct SkipNullValuesMapVisitor<K, V> {
    marker: PhantomData<fn() -> HashMap<K, V>>,
}

impl<'de, K, V> Visitor<'de> for SkipNullValuesMapVisitor<K, V>
where
    K: Deserialize<'de> + Eq + Hash,
    V: Deserialize<'de>,
{
    type Value = HashMap<K, V>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a very special map")
    }

    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>,
    {
        let mut map = HashMap::with_capacity(access.size_hint().unwrap_or(0));

        // While there are entries remaining in the input, add them
        // into our map.
        while let Some((key, value)) = access.next_entry::<K, Option<V>>()? {
            if let Some(value) = value {
                map.insert(key, value);
            }
        }

        Ok(map)
    }
}

struct OptionSkipNullValuesMapVisitor<T> {
    marker: PhantomData<T>,
}

impl<'de, K, V> Visitor<'de> for OptionSkipNullValuesMapVisitor<HashMap<K, V>>
where
    K: Deserialize<'de> + Eq + Hash,
    V: Deserialize<'de>,
{
    type Value = Option<HashMap<K, V>>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("option")
    }

    #[inline]
    fn visit_unit<E>(self) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(None)
    }

    #[inline]
    fn visit_none<E>(self) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(None)
    }

    #[inline]
    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserialize_map_without_null_values(deserializer).map(Some)
    }

    #[doc(hidden)]
    fn __private_visit_untagged_option<D>(self, deserializer: D) -> Result<Self::Value, ()>
    where
        D: Deserializer<'de>,
    {
        Ok(deserialize_map_without_null_values(deserializer).ok())
    }
}