]> git.proxmox.com Git - rustc.git/blob - vendor/zerovec/src/map2d/serde.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / vendor / zerovec / src / map2d / 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
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 {
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 {
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 {
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 {
114 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
134 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
135 formatter.write_str("a map produced by ZeroMap2d")
136 }
137
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> {
180 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
194 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
195 formatter.write_str("an inner map produced by ZeroMap2d")
196 }
197
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 {
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 {
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 {
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, 20, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
373 3, 0, 6, 0, 117, 110, 111, 100, 111, 115, 116, 114, 101, 115,
374 ];
375
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]
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]
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]
417 fn test_sample_bincode() {
418 // This is the map from the main docs page for ZeroMap2d
419 let mut map: ZeroMap2d<u16, u16, str> = ZeroMap2d::new();
420 map.insert(&1, &2, "three");
421 let bincode_bytes: Vec<u8> = bincode::serialize(&map).expect("serialize");
422 assert_eq!(
423 bincode_bytes.as_slice(),
424 &[
425 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,
426 0, 0, 2, 0, 11, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 116, 104, 114, 101, 101
427 ]
428 );
429 }
430 }