openconfiguration/
utils.rs

1use std::collections::HashMap;
2use std::{fmt, hash::Hash, marker::PhantomData};
3
4use serde::{
5    de::{MapAccess, Visitor},
6    Deserialize, Deserializer,
7};
8
9pub fn deserialize_optional_map_without_null_values<'de, D, K, V>(
10    deserializer: D,
11) -> Result<Option<HashMap<K, V>>, D::Error>
12where
13    D: Deserializer<'de>,
14    K: Deserialize<'de> + Hash + Eq,
15    V: Deserialize<'de>,
16{
17    deserializer.deserialize_option(OptionSkipNullValuesMapVisitor {
18        marker: PhantomData,
19    })
20}
21
22pub fn deserialize_map_without_null_values<'de, D, K, V>(
23    deserializer: D,
24) -> Result<HashMap<K, V>, D::Error>
25where
26    D: Deserializer<'de>,
27    K: Deserialize<'de> + Hash + Eq,
28    V: Deserialize<'de>,
29{
30    deserializer.deserialize_map(SkipNullValuesMapVisitor {
31        marker: PhantomData,
32    })
33}
34
35struct SkipNullValuesMapVisitor<K, V> {
36    marker: PhantomData<fn() -> HashMap<K, V>>,
37}
38
39impl<'de, K, V> Visitor<'de> for SkipNullValuesMapVisitor<K, V>
40where
41    K: Deserialize<'de> + Eq + Hash,
42    V: Deserialize<'de>,
43{
44    type Value = HashMap<K, V>;
45
46    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
47        formatter.write_str("a very special map")
48    }
49
50    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
51    where
52        M: MapAccess<'de>,
53    {
54        let mut map = HashMap::with_capacity(access.size_hint().unwrap_or(0));
55
56        // While there are entries remaining in the input, add them
57        // into our map.
58        while let Some((key, value)) = access.next_entry::<K, Option<V>>()? {
59            if let Some(value) = value {
60                map.insert(key, value);
61            }
62        }
63
64        Ok(map)
65    }
66}
67
68struct OptionSkipNullValuesMapVisitor<T> {
69    marker: PhantomData<T>,
70}
71
72impl<'de, K, V> Visitor<'de> for OptionSkipNullValuesMapVisitor<HashMap<K, V>>
73where
74    K: Deserialize<'de> + Eq + Hash,
75    V: Deserialize<'de>,
76{
77    type Value = Option<HashMap<K, V>>;
78
79    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
80        formatter.write_str("option")
81    }
82
83    #[inline]
84    fn visit_unit<E>(self) -> Result<Self::Value, E>
85    where
86        E: serde::de::Error,
87    {
88        Ok(None)
89    }
90
91    #[inline]
92    fn visit_none<E>(self) -> Result<Self::Value, E>
93    where
94        E: serde::de::Error,
95    {
96        Ok(None)
97    }
98
99    #[inline]
100    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
101    where
102        D: Deserializer<'de>,
103    {
104        deserialize_map_without_null_values(deserializer).map(Some)
105    }
106
107    #[doc(hidden)]
108    fn __private_visit_untagged_option<D>(self, deserializer: D) -> Result<Self::Value, ()>
109    where
110        D: Deserializer<'de>,
111    {
112        Ok(deserialize_map_without_null_values(deserializer).ok())
113    }
114}