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}