• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 use super::{ZeroMap2d, ZeroMap2dBorrowed, ZeroMap2dCursor};
6 use crate::map::{MutableZeroVecLike, ZeroMapKV, ZeroVecLike};
7 use crate::ZeroVec;
8 use alloc::vec::Vec;
9 use core::fmt;
10 use core::marker::PhantomData;
11 use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor};
12 #[cfg(feature = "serde")]
13 use serde::ser::{Serialize, SerializeMap, Serializer};
14 
15 /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
16 #[cfg(feature = "serde")]
17 impl<'a, K0, K1, V> Serialize for ZeroMap2d<'a, K0, K1, V>
18 where
19     K0: ZeroMapKV<'a> + Serialize + ?Sized + Ord,
20     K1: ZeroMapKV<'a> + Serialize + ?Sized + Ord,
21     V: ZeroMapKV<'a> + Serialize + ?Sized,
22     K0::Container: Serialize,
23     K1::Container: Serialize,
24     V::Container: Serialize,
25 {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,26     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27     where
28         S: Serializer,
29     {
30         if serializer.is_human_readable() {
31             let mut serde_map = serializer.serialize_map(None)?;
32             for cursor in self.iter0() {
33                 K0::Container::zvl_get_as_t(cursor.key0(), |k| serde_map.serialize_key(k))?;
34                 let inner_map = ZeroMap2dInnerMapSerialize { cursor };
35                 serde_map.serialize_value(&inner_map)?;
36             }
37             serde_map.end()
38         } else {
39             (&self.keys0, &self.joiner, &self.keys1, &self.values).serialize(serializer)
40         }
41     }
42 }
43 
44 /// Helper struct for human-serializing the inner map of a ZeroMap2d
45 #[cfg(feature = "serde")]
46 struct ZeroMap2dInnerMapSerialize<'a, 'l, K0, K1, V>
47 where
48     K0: ZeroMapKV<'a> + ?Sized + Ord,
49     K1: ZeroMapKV<'a> + ?Sized + Ord,
50     V: ZeroMapKV<'a> + ?Sized,
51 {
52     pub cursor: ZeroMap2dCursor<'l, 'a, K0, K1, V>,
53 }
54 
55 #[cfg(feature = "serde")]
56 impl<'a, 'l, K0, K1, V> Serialize for ZeroMap2dInnerMapSerialize<'a, 'l, K0, K1, V>
57 where
58     K0: ZeroMapKV<'a> + Serialize + ?Sized + Ord,
59     K1: ZeroMapKV<'a> + Serialize + ?Sized + Ord,
60     V: ZeroMapKV<'a> + Serialize + ?Sized,
61     K0::Container: Serialize,
62     K1::Container: Serialize,
63     V::Container: Serialize,
64 {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,65     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
66     where
67         S: Serializer,
68     {
69         let mut serde_map = serializer.serialize_map(None)?;
70         for (key1, v) in self.cursor.iter1() {
71             K1::Container::zvl_get_as_t(key1, |k| serde_map.serialize_key(k))?;
72             V::Container::zvl_get_as_t(v, |v| serde_map.serialize_value(v))?;
73         }
74         serde_map.end()
75     }
76 }
77 
78 /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
79 #[cfg(feature = "serde")]
80 impl<'a, K0, K1, V> Serialize for ZeroMap2dBorrowed<'a, K0, K1, V>
81 where
82     K0: ZeroMapKV<'a> + Serialize + ?Sized + Ord,
83     K1: ZeroMapKV<'a> + Serialize + ?Sized + Ord,
84     V: ZeroMapKV<'a> + Serialize + ?Sized,
85     K0::Container: Serialize,
86     K1::Container: Serialize,
87     V::Container: Serialize,
88 {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,89     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
90     where
91         S: Serializer,
92     {
93         ZeroMap2d::<K0, K1, V>::from(*self).serialize(serializer)
94     }
95 }
96 
97 /// Modified example from https://serde.rs/deserialize-map.html
98 struct ZeroMap2dMapVisitor<'a, K0, K1, V>
99 where
100     K0: ZeroMapKV<'a> + ?Sized + Ord,
101     K1: ZeroMapKV<'a> + ?Sized + Ord,
102     V: ZeroMapKV<'a> + ?Sized,
103 {
104     #[allow(clippy::type_complexity)] // it's a marker type, complexity doesn't matter
105     marker: PhantomData<fn() -> (&'a K0::OwnedType, &'a K1::OwnedType, &'a V::OwnedType)>,
106 }
107 
108 impl<'a, K0, K1, V> ZeroMap2dMapVisitor<'a, K0, K1, V>
109 where
110     K0: ZeroMapKV<'a> + ?Sized + Ord,
111     K1: ZeroMapKV<'a> + ?Sized + Ord,
112     V: ZeroMapKV<'a> + ?Sized,
113 {
new() -> Self114     fn new() -> Self {
115         ZeroMap2dMapVisitor {
116             marker: PhantomData,
117         }
118     }
119 }
120 
121 impl<'a, 'de, K0, K1, V> Visitor<'de> for ZeroMap2dMapVisitor<'a, K0, K1, V>
122 where
123     K0: ZeroMapKV<'a> + Ord + ?Sized + Ord,
124     K1: ZeroMapKV<'a> + Ord + ?Sized + Ord,
125     V: ZeroMapKV<'a> + ?Sized,
126     K1::Container: Deserialize<'de>,
127     V::Container: Deserialize<'de>,
128     K0::OwnedType: Deserialize<'de>,
129     K1::OwnedType: Deserialize<'de>,
130     V::OwnedType: Deserialize<'de>,
131 {
132     type Value = ZeroMap2d<'a, K0, K1, V>;
133 
expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result134     fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
135         formatter.write_str("a map produced by ZeroMap2d")
136     }
137 
visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error> where M: MapAccess<'de>,138     fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
139     where
140         M: MapAccess<'de>,
141     {
142         let mut map = ZeroMap2d::with_capacity(access.size_hint().unwrap_or(0));
143 
144         // On the first level, pull out the K0s and a TupleVecMap of the
145         // K1s and Vs, and then collect them into a ZeroMap2d
146         while let Some((key0, inner_map)) =
147             access.next_entry::<K0::OwnedType, TupleVecMap<K1::OwnedType, V::OwnedType>>()?
148         {
149             for (key1, value) in inner_map.entries.iter() {
150                 if map
151                     .try_append(
152                         K0::Container::owned_as_t(&key0),
153                         K1::Container::owned_as_t(key1),
154                         V::Container::owned_as_t(value),
155                     )
156                     .is_some()
157                 {
158                     return Err(de::Error::custom(
159                         "ZeroMap2d's keys must be sorted while deserializing",
160                     ));
161                 }
162             }
163         }
164 
165         Ok(map)
166     }
167 }
168 
169 /// Helper struct for human-deserializing the inner map of a ZeroMap2d
170 struct TupleVecMap<K1, V> {
171     pub entries: Vec<(K1, V)>,
172 }
173 
174 struct TupleVecMapVisitor<K1, V> {
175     #[allow(clippy::type_complexity)] // it's a marker type, complexity doesn't matter
176     marker: PhantomData<fn() -> (K1, V)>,
177 }
178 
179 impl<K1, V> TupleVecMapVisitor<K1, V> {
new() -> Self180     fn new() -> Self {
181         TupleVecMapVisitor {
182             marker: PhantomData,
183         }
184     }
185 }
186 
187 impl<'de, K1, V> Visitor<'de> for TupleVecMapVisitor<K1, V>
188 where
189     K1: Deserialize<'de>,
190     V: Deserialize<'de>,
191 {
192     type Value = TupleVecMap<K1, V>;
193 
expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result194     fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
195         formatter.write_str("an inner map produced by ZeroMap2d")
196     }
197 
visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error> where M: MapAccess<'de>,198     fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
199     where
200         M: MapAccess<'de>,
201     {
202         let mut result = Vec::with_capacity(access.size_hint().unwrap_or(0));
203         while let Some((key1, value)) = access.next_entry::<K1, V>()? {
204             result.push((key1, value));
205         }
206         Ok(TupleVecMap { entries: result })
207     }
208 }
209 
210 impl<'de, K1, V> Deserialize<'de> for TupleVecMap<K1, V>
211 where
212     K1: Deserialize<'de>,
213     V: Deserialize<'de>,
214 {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,215     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
216     where
217         D: Deserializer<'de>,
218     {
219         deserializer.deserialize_map(TupleVecMapVisitor::<K1, V>::new())
220     }
221 }
222 
223 /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
224 impl<'de, 'a, K0, K1, V> Deserialize<'de> for ZeroMap2d<'a, K0, K1, V>
225 where
226     K0: ZeroMapKV<'a> + Ord + ?Sized,
227     K1: ZeroMapKV<'a> + Ord + ?Sized,
228     V: ZeroMapKV<'a> + ?Sized,
229     K0::Container: Deserialize<'de>,
230     K1::Container: Deserialize<'de>,
231     V::Container: Deserialize<'de>,
232     K0::OwnedType: Deserialize<'de>,
233     K1::OwnedType: Deserialize<'de>,
234     V::OwnedType: Deserialize<'de>,
235     'de: 'a,
236 {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,237     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
238     where
239         D: Deserializer<'de>,
240     {
241         if deserializer.is_human_readable() {
242             deserializer.deserialize_map(ZeroMap2dMapVisitor::<'a, K0, K1, V>::new())
243         } else {
244             let (keys0, joiner, keys1, values): (
245                 K0::Container,
246                 ZeroVec<u32>,
247                 K1::Container,
248                 V::Container,
249             ) = Deserialize::deserialize(deserializer)?;
250             // Invariant 1: len(keys0) == len(joiner)
251             if keys0.zvl_len() != joiner.len() {
252                 return Err(de::Error::custom(
253                     "Mismatched keys0 and joiner sizes in ZeroMap2d",
254                 ));
255             }
256             // Invariant 2: len(keys1) == len(values)
257             if keys1.zvl_len() != values.zvl_len() {
258                 return Err(de::Error::custom(
259                     "Mismatched keys1 and value sizes in ZeroMap2d",
260                 ));
261             }
262             // Invariant 3: joiner is sorted
263             if !joiner.zvl_is_ascending() {
264                 return Err(de::Error::custom(
265                     "ZeroMap2d deserializing joiner array out of order",
266                 ));
267             }
268             // Invariant 4: the last element of joiner is the length of keys1
269             if let Some(last_joiner0) = joiner.last() {
270                 if keys1.zvl_len() != last_joiner0 as usize {
271                     return Err(de::Error::custom(
272                         "ZeroMap2d deserializing joiner array malformed",
273                     ));
274                 }
275             }
276             let result = Self {
277                 keys0,
278                 joiner,
279                 keys1,
280                 values,
281             };
282             // In debug mode, check the optional invariants, too
283             #[cfg(debug_assertions)]
284             result.check_invariants();
285             Ok(result)
286         }
287     }
288 }
289 
290 /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
291 impl<'de, 'a, K0, K1, V> Deserialize<'de> for ZeroMap2dBorrowed<'a, K0, K1, V>
292 where
293     K0: ZeroMapKV<'a> + Ord + ?Sized,
294     K1: ZeroMapKV<'a> + Ord + ?Sized,
295     V: ZeroMapKV<'a> + ?Sized,
296     K0::Container: Deserialize<'de>,
297     K1::Container: Deserialize<'de>,
298     V::Container: Deserialize<'de>,
299     K0::OwnedType: Deserialize<'de>,
300     K1::OwnedType: Deserialize<'de>,
301     V::OwnedType: Deserialize<'de>,
302     'de: 'a,
303 {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,304     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
305     where
306         D: Deserializer<'de>,
307     {
308         if deserializer.is_human_readable() {
309             Err(de::Error::custom(
310                 "ZeroMap2dBorrowed cannot be deserialized from human-readable formats",
311             ))
312         } else {
313             let deserialized: ZeroMap2d<'a, K0, K1, V> = ZeroMap2d::deserialize(deserializer)?;
314             let keys0 = if let Some(keys0) = deserialized.keys0.zvl_as_borrowed_inner() {
315                 keys0
316             } else {
317                 return Err(de::Error::custom(
318                     "ZeroMap2dBorrowed can only deserialize in zero-copy ways",
319                 ));
320             };
321             let joiner = if let Some(joiner) = deserialized.joiner.zvl_as_borrowed_inner() {
322                 joiner
323             } else {
324                 return Err(de::Error::custom(
325                     "ZeroMap2dBorrowed can only deserialize in zero-copy ways",
326                 ));
327             };
328             let keys1 = if let Some(keys1) = deserialized.keys1.zvl_as_borrowed_inner() {
329                 keys1
330             } else {
331                 return Err(de::Error::custom(
332                     "ZeroMap2dBorrowed can only deserialize in zero-copy ways",
333                 ));
334             };
335             let values = if let Some(values) = deserialized.values.zvl_as_borrowed_inner() {
336                 values
337             } else {
338                 return Err(de::Error::custom(
339                     "ZeroMap2dBorrowed can only deserialize in zero-copy ways",
340                 ));
341             };
342             Ok(Self {
343                 keys0,
344                 joiner,
345                 keys1,
346                 values,
347             })
348         }
349     }
350 }
351 
352 #[cfg(test)]
353 #[allow(non_camel_case_types)]
354 mod test {
355     use crate::map2d::{ZeroMap2d, ZeroMap2dBorrowed};
356 
357     #[derive(serde::Serialize, serde::Deserialize)]
358     struct DeriveTest_ZeroMap2d<'data> {
359         #[serde(borrow)]
360         _data: ZeroMap2d<'data, u16, str, [u8]>,
361     }
362 
363     #[derive(serde::Serialize, serde::Deserialize)]
364     struct DeriveTest_ZeroMap2dBorrowed<'data> {
365         #[serde(borrow)]
366         _data: ZeroMap2dBorrowed<'data, u16, str, [u8]>,
367     }
368 
369     const JSON_STR: &str = "{\"1\":{\"1\":\"uno\"},\"2\":{\"2\":\"dos\",\"3\":\"tres\"}}";
370     const BINCODE_BYTES: &[u8] = &[
371         8, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0,
372         0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 16, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 6, 0,
373         117, 110, 111, 100, 111, 115, 116, 114, 101, 115,
374     ];
375 
make_map() -> ZeroMap2d<'static, u32, u16, str>376     fn make_map() -> ZeroMap2d<'static, u32, u16, str> {
377         let mut map = ZeroMap2d::new();
378         map.insert(&1, &1, "uno");
379         map.insert(&2, &2, "dos");
380         map.insert(&2, &3, "tres");
381         map
382     }
383 
384     #[test]
test_serde_json()385     fn test_serde_json() {
386         let map = make_map();
387         let json_str = serde_json::to_string(&map).expect("serialize");
388         assert_eq!(JSON_STR, json_str);
389         let new_map: ZeroMap2d<u32, u16, str> =
390             serde_json::from_str(&json_str).expect("deserialize");
391         assert_eq!(format!("{new_map:?}"), format!("{map:?}"));
392     }
393 
394     #[test]
test_bincode()395     fn test_bincode() {
396         let map = make_map();
397         let bincode_bytes = bincode::serialize(&map).expect("serialize");
398         assert_eq!(BINCODE_BYTES, bincode_bytes);
399         let new_map: ZeroMap2d<u32, u16, str> =
400             bincode::deserialize(&bincode_bytes).expect("deserialize");
401         assert_eq!(
402             format!("{new_map:?}"),
403             format!("{map:?}").replace("Owned", "Borrowed"),
404         );
405 
406         let new_map: ZeroMap2dBorrowed<u32, u16, str> =
407             bincode::deserialize(&bincode_bytes).expect("deserialize");
408         assert_eq!(
409             format!("{new_map:?}"),
410             format!("{map:?}")
411                 .replace("Owned", "Borrowed")
412                 .replace("ZeroMap2d", "ZeroMap2dBorrowed")
413         );
414     }
415 
416     #[test]
test_serde_rmp()417     fn test_serde_rmp() {
418         let map = make_map();
419         let rmp_buf = rmp_serde::to_vec(&map).expect("serialize");
420         let new_map: ZeroMap2d<u32, u16, str> = rmp_serde::from_slice(&rmp_buf).unwrap();
421         assert_eq!(map, new_map);
422     }
423 
424     #[test]
test_sample_bincode()425     fn test_sample_bincode() {
426         // This is the map from the main docs page for ZeroMap2d
427         let mut map: ZeroMap2d<u16, u16, str> = ZeroMap2d::new();
428         map.insert(&1, &2, "three");
429         let bincode_bytes: Vec<u8> = bincode::serialize(&map).expect("serialize");
430         assert_eq!(
431             bincode_bytes.as_slice(),
432             &[
433                 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0,
434                 0, 0, 2, 0, 7, 0, 0, 0, 0, 0, 0, 0, 1, 0, 116, 104, 114, 101, 101
435             ]
436         );
437     }
438 }
439