serde_partial/
std.rs

1use core::{
2    hash::{BuildHasher, Hash},
3    iter::Map,
4};
5use std::collections::{
6    hash_map::{HashMap, Keys},
7    HashSet,
8};
9
10use serde::Serialize;
11
12use crate::{Field, Partial, SerializeFilter, SerializePartial};
13
14impl<'a, K, V, S> SerializePartial<'a> for HashMap<K, V, S>
15where
16    K: Hash + Eq + AsRef<str> + Serialize + 'a,
17    V: Serialize + 'a,
18    S: BuildHasher + Default + 'a,
19{
20    #[allow(clippy::type_complexity)]
21    type Fields = Map<Keys<'a, K, V>, fn(&'a K) -> Field<'a, Self>>;
22    type Filter = HashSet<Field<'a, Self>, S>;
23
24    fn with_fields<F, I>(&'a self, select: F) -> Partial<'a, Self>
25    where
26        F: FnOnce(Self::Fields) -> I,
27        I: IntoIterator<Item = Field<'a, Self>>,
28    {
29        let fields: Self::Fields = self.keys().map(|k| Field::new(k.as_ref()));
30        let filter = select(fields).into_iter().collect();
31        Partial {
32            value: self,
33            filter,
34        }
35    }
36}
37
38impl<'a, K, V, S> SerializeFilter<HashMap<K, V, S>> for HashSet<Field<'a, HashMap<K, V, S>>, S>
39where
40    S: BuildHasher,
41{
42    fn skip(&self, field: Field<'_, HashMap<K, V, S>>) -> bool {
43        !self.contains(&field)
44    }
45
46    fn filtered_len(&self, _len: Option<usize>) -> Option<usize> {
47        Some(self.len())
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use crate::{Field, SerializePartial};
54
55    use std::collections::HashMap;
56
57    #[test]
58    fn hash_map() {
59        let map = HashMap::from([("a", "b"), ("c", "d")]);
60        let filtered = map.with_fields(|_| [Field::new("a")]);
61        assert_eq!(
62            serde_json::to_value(&filtered).unwrap(),
63            serde_json::json!({ "a": "b" })
64        )
65    }
66}