zerovec/hashmap/
serde.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use super::ZeroHashMap;
6use crate::{
7    map::{ZeroMapKV, ZeroVecLike},
8    ZeroVec,
9};
10
11use serde::{de, Deserialize, Serialize};
12
13impl<'a, K, V> Serialize for ZeroHashMap<'a, K, V>
14where
15    K: ZeroMapKV<'a> + Serialize + ?Sized,
16    V: ZeroMapKV<'a> + Serialize + ?Sized,
17    K::Container: Serialize,
18    V::Container: Serialize,
19{
20    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
21    where
22        S: serde::Serializer,
23    {
24        (&self.displacements, &self.keys, &self.values).serialize(serializer)
25    }
26}
27
28impl<'de, 'a, K, V> Deserialize<'de> for ZeroHashMap<'a, K, V>
29where
30    K: ZeroMapKV<'a> + ?Sized,
31    V: ZeroMapKV<'a> + ?Sized,
32    K::Container: Deserialize<'de>,
33    V::Container: Deserialize<'de>,
34    'de: 'a,
35{
36    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
37    where
38        D: serde::Deserializer<'de>,
39    {
40        let (displacements, keys, values): (ZeroVec<(u32, u32)>, K::Container, V::Container) =
41            Deserialize::deserialize(deserializer)?;
42        if keys.zvl_len() != values.zvl_len() {
43            return Err(de::Error::custom(
44                "Mismatched key and value sizes in ZeroHashMap",
45            ));
46        }
47        if displacements.zvl_len() != keys.zvl_len() {
48            return Err(de::Error::custom(
49                "Mismatched displacements and key, value sizes in ZeroHashMap",
50            ));
51        }
52        Ok(Self {
53            displacements,
54            keys,
55            values,
56        })
57    }
58}
59
60#[cfg(test)]
61mod test {
62    use crate::{VarZeroVec, ZeroHashMap, ZeroVec};
63    use serde::{Deserialize, Serialize};
64
65    const JSON_STR: &str = "[[[0,0],[0,1],[0,1]],[1,2,0],[\"b\",\"c\",\"a\"]]";
66
67    const BINCODE_BYTES: &[u8] = &[
68        24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
69        0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
70        3, 0, 1, 0, 2, 0, 98, 99, 97,
71    ];
72
73    #[derive(Serialize, Deserialize)]
74    struct DeriveTestZeroHashMap<'data> {
75        #[serde(borrow)]
76        _data: ZeroHashMap<'data, str, [u8]>,
77    }
78
79    fn make_zerohashmap() -> ZeroHashMap<'static, u32, str> {
80        ZeroHashMap::from_iter([(0, "a"), (1, "b"), (2, "c")])
81    }
82
83    fn build_invalid_hashmap_str(
84        displacements: Vec<(u32, u32)>,
85        keys: Vec<u32>,
86        values: Vec<&str>,
87    ) -> String {
88        let invalid_hm: ZeroHashMap<u32, str> = ZeroHashMap {
89            displacements: ZeroVec::alloc_from_slice(&displacements),
90            keys: ZeroVec::alloc_from_slice(&keys),
91            values: VarZeroVec::<str>::from(&values),
92        };
93        serde_json::to_string(&invalid_hm).expect("serialize")
94    }
95
96    #[test]
97    fn test_invalid_deser_zhm() {
98        // Invalid hashmap |keys| != |values|
99        let mut invalid_hm_str =
100            build_invalid_hashmap_str(vec![(0, 1), (0, 0)], vec![1, 2], vec!["a", "b", "c"]);
101
102        assert_eq!(
103            serde_json::from_str::<ZeroHashMap<u32, str>>(&invalid_hm_str)
104                .unwrap_err()
105                .to_string(),
106            "Mismatched key and value sizes in ZeroHashMap"
107        );
108
109        // Invalid hashmap |displacements| != |keys| == |values|
110        // |displacements| = 2, |keys| = 3, |values| = 3
111        invalid_hm_str =
112            build_invalid_hashmap_str(vec![(0, 1), (0, 0)], vec![2, 1, 0], vec!["a", "b", "c"]);
113
114        assert_eq!(
115            serde_json::from_str::<ZeroHashMap<u32, str>>(&invalid_hm_str)
116                .unwrap_err()
117                .to_string(),
118            "Mismatched displacements and key, value sizes in ZeroHashMap"
119        );
120    }
121
122    #[test]
123    fn test_serde_valid_deser_zhm() {
124        let hm = make_zerohashmap();
125        let json_str = serde_json::to_string(&hm).expect("serialize");
126        assert_eq!(json_str, JSON_STR);
127        let deserialized_hm: ZeroHashMap<u32, str> =
128            serde_json::from_str(JSON_STR).expect("deserialize");
129        assert_eq!(
130            hm.iter().collect::<Vec<_>>(),
131            deserialized_hm.iter().collect::<Vec<_>>()
132        );
133    }
134
135    #[test]
136    fn test_bincode_zhm() {
137        let hm = make_zerohashmap();
138        let bincode_bytes = bincode::serialize(&hm).expect("serialize");
139        assert_eq!(bincode_bytes, BINCODE_BYTES);
140        let deserialized_hm: ZeroHashMap<u32, str> =
141            bincode::deserialize(BINCODE_BYTES).expect("deserialize");
142        assert_eq!(
143            hm.iter().collect::<Vec<_>>(),
144            deserialized_hm.iter().collect::<Vec<_>>()
145        );
146    }
147}