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 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())
}
}