diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:21 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:21 +0000 |
commit | 4e8199b572f2035b7749cba276ece3a26630d23e (patch) | |
tree | f09feeed6a0fe39d027b1908aa63ea6b35e4b631 /vendor/zerovec/src/map2d/serde.rs | |
parent | Adding upstream version 1.66.0+dfsg1. (diff) | |
download | rustc-4e8199b572f2035b7749cba276ece3a26630d23e.tar.xz rustc-4e8199b572f2035b7749cba276ece3a26630d23e.zip |
Adding upstream version 1.67.1+dfsg1.upstream/1.67.1+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/zerovec/src/map2d/serde.rs')
-rw-r--r-- | vendor/zerovec/src/map2d/serde.rs | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/vendor/zerovec/src/map2d/serde.rs b/vendor/zerovec/src/map2d/serde.rs new file mode 100644 index 000000000..f8b5f147b --- /dev/null +++ b/vendor/zerovec/src/map2d/serde.rs @@ -0,0 +1,430 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use super::{ZeroMap2d, ZeroMap2dBorrowed, ZeroMap2dCursor}; +use crate::map::{MutableZeroVecLike, ZeroMapKV, ZeroVecLike}; +use crate::ZeroVec; +use alloc::vec::Vec; +use core::fmt; +use core::marker::PhantomData; +use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor}; +#[cfg(feature = "serde")] +use serde::ser::{Serialize, SerializeMap, Serializer}; + +/// This impl can be made available by enabling the optional `serde` feature of the `zerovec` crate +#[cfg(feature = "serde")] +impl<'a, K0, K1, V> Serialize for ZeroMap2d<'a, K0, K1, V> +where + K0: ZeroMapKV<'a> + Serialize + ?Sized + Ord, + K1: ZeroMapKV<'a> + Serialize + ?Sized + Ord, + V: ZeroMapKV<'a> + Serialize + ?Sized, + K0::Container: Serialize, + K1::Container: Serialize, + V::Container: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + if serializer.is_human_readable() { + let mut serde_map = serializer.serialize_map(None)?; + for cursor in self.iter0() { + K0::Container::zvl_get_as_t(cursor.key0(), |k| serde_map.serialize_key(k))?; + let inner_map = ZeroMap2dInnerMapSerialize { cursor }; + serde_map.serialize_value(&inner_map)?; + } + serde_map.end() + } else { + (&self.keys0, &self.joiner, &self.keys1, &self.values).serialize(serializer) + } + } +} + +/// Helper struct for human-serializing the inner map of a ZeroMap2d +#[cfg(feature = "serde")] +struct ZeroMap2dInnerMapSerialize<'a, 'l, K0, K1, V> +where + K0: ZeroMapKV<'a> + ?Sized + Ord, + K1: ZeroMapKV<'a> + ?Sized + Ord, + V: ZeroMapKV<'a> + ?Sized, +{ + pub cursor: ZeroMap2dCursor<'l, 'a, K0, K1, V>, +} + +#[cfg(feature = "serde")] +impl<'a, 'l, K0, K1, V> Serialize for ZeroMap2dInnerMapSerialize<'a, 'l, K0, K1, V> +where + K0: ZeroMapKV<'a> + Serialize + ?Sized + Ord, + K1: ZeroMapKV<'a> + Serialize + ?Sized + Ord, + V: ZeroMapKV<'a> + Serialize + ?Sized, + K0::Container: Serialize, + K1::Container: Serialize, + V::Container: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut serde_map = serializer.serialize_map(None)?; + for (key1, v) in self.cursor.iter1() { + K1::Container::zvl_get_as_t(key1, |k| serde_map.serialize_key(k))?; + V::Container::zvl_get_as_t(v, |v| serde_map.serialize_value(v))?; + } + serde_map.end() + } +} + +/// This impl can be made available by enabling the optional `serde` feature of the `zerovec` crate +#[cfg(feature = "serde")] +impl<'a, K0, K1, V> Serialize for ZeroMap2dBorrowed<'a, K0, K1, V> +where + K0: ZeroMapKV<'a> + Serialize + ?Sized + Ord, + K1: ZeroMapKV<'a> + Serialize + ?Sized + Ord, + V: ZeroMapKV<'a> + Serialize + ?Sized, + K0::Container: Serialize, + K1::Container: Serialize, + V::Container: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + ZeroMap2d::<K0, K1, V>::from(*self).serialize(serializer) + } +} + +/// Modified example from https://serde.rs/deserialize-map.html +struct ZeroMap2dMapVisitor<'a, K0, K1, V> +where + K0: ZeroMapKV<'a> + ?Sized + Ord, + K1: ZeroMapKV<'a> + ?Sized + Ord, + V: ZeroMapKV<'a> + ?Sized, +{ + #[allow(clippy::type_complexity)] // it's a marker type, complexity doesn't matter + marker: PhantomData<fn() -> (&'a K0::OwnedType, &'a K1::OwnedType, &'a V::OwnedType)>, +} + +impl<'a, K0, K1, V> ZeroMap2dMapVisitor<'a, K0, K1, V> +where + K0: ZeroMapKV<'a> + ?Sized + Ord, + K1: ZeroMapKV<'a> + ?Sized + Ord, + V: ZeroMapKV<'a> + ?Sized, +{ + fn new() -> Self { + ZeroMap2dMapVisitor { + marker: PhantomData, + } + } +} + +impl<'a, 'de, K0, K1, V> Visitor<'de> for ZeroMap2dMapVisitor<'a, K0, K1, V> +where + K0: ZeroMapKV<'a> + Ord + ?Sized + Ord, + K1: ZeroMapKV<'a> + Ord + ?Sized + Ord, + V: ZeroMapKV<'a> + ?Sized, + K1::Container: Deserialize<'de>, + V::Container: Deserialize<'de>, + K0::OwnedType: Deserialize<'de>, + K1::OwnedType: Deserialize<'de>, + V::OwnedType: Deserialize<'de>, +{ + type Value = ZeroMap2d<'a, K0, K1, V>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map produced by ZeroMap2d") + } + + fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error> + where + M: MapAccess<'de>, + { + let mut map = ZeroMap2d::with_capacity(access.size_hint().unwrap_or(0)); + + // On the first level, pull out the K0s and a TupleVecMap of the + // K1s and Vs, and then collect them into a ZeroMap2d + while let Some((key0, inner_map)) = + access.next_entry::<K0::OwnedType, TupleVecMap<K1::OwnedType, V::OwnedType>>()? + { + for (key1, value) in inner_map.entries.iter() { + if map + .try_append( + K0::Container::owned_as_t(&key0), + K1::Container::owned_as_t(key1), + V::Container::owned_as_t(value), + ) + .is_some() + { + return Err(de::Error::custom( + "ZeroMap2d's keys must be sorted while deserializing", + )); + } + } + } + + Ok(map) + } +} + +/// Helper struct for human-deserializing the inner map of a ZeroMap2d +struct TupleVecMap<K1, V> { + pub entries: Vec<(K1, V)>, +} + +struct TupleVecMapVisitor<K1, V> { + #[allow(clippy::type_complexity)] // it's a marker type, complexity doesn't matter + marker: PhantomData<fn() -> (K1, V)>, +} + +impl<K1, V> TupleVecMapVisitor<K1, V> { + fn new() -> Self { + TupleVecMapVisitor { + marker: PhantomData, + } + } +} + +impl<'de, K1, V> Visitor<'de> for TupleVecMapVisitor<K1, V> +where + K1: Deserialize<'de>, + V: Deserialize<'de>, +{ + type Value = TupleVecMap<K1, V>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an inner map produced by ZeroMap2d") + } + + fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error> + where + M: MapAccess<'de>, + { + let mut result = Vec::with_capacity(access.size_hint().unwrap_or(0)); + while let Some((key1, value)) = access.next_entry::<K1, V>()? { + result.push((key1, value)); + } + Ok(TupleVecMap { entries: result }) + } +} + +impl<'de, K1, V> Deserialize<'de> for TupleVecMap<K1, V> +where + K1: Deserialize<'de>, + V: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(TupleVecMapVisitor::<K1, V>::new()) + } +} + +/// This impl can be made available by enabling the optional `serde` feature of the `zerovec` crate +impl<'de, 'a, K0, K1, V> Deserialize<'de> for ZeroMap2d<'a, K0, K1, V> +where + K0: ZeroMapKV<'a> + Ord + ?Sized, + K1: ZeroMapKV<'a> + Ord + ?Sized, + V: ZeroMapKV<'a> + ?Sized, + K0::Container: Deserialize<'de>, + K1::Container: Deserialize<'de>, + V::Container: Deserialize<'de>, + K0::OwnedType: Deserialize<'de>, + K1::OwnedType: Deserialize<'de>, + V::OwnedType: Deserialize<'de>, + 'de: 'a, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_map(ZeroMap2dMapVisitor::<'a, K0, K1, V>::new()) + } else { + let (keys0, joiner, keys1, values): ( + K0::Container, + ZeroVec<u32>, + K1::Container, + V::Container, + ) = Deserialize::deserialize(deserializer)?; + // Invariant 1: len(keys0) == len(joiner) + if keys0.zvl_len() != joiner.len() { + return Err(de::Error::custom( + "Mismatched keys0 and joiner sizes in ZeroMap2d", + )); + } + // Invariant 2: len(keys1) == len(values) + if keys1.zvl_len() != values.zvl_len() { + return Err(de::Error::custom( + "Mismatched keys1 and value sizes in ZeroMap2d", + )); + } + // Invariant 3: joiner is sorted + if !joiner.zvl_is_ascending() { + return Err(de::Error::custom( + "ZeroMap2d deserializing joiner array out of order", + )); + } + // Invariant 4: the last element of joiner is the length of keys1 + if let Some(last_joiner0) = joiner.last() { + if keys1.zvl_len() != last_joiner0 as usize { + return Err(de::Error::custom( + "ZeroMap2d deserializing joiner array malformed", + )); + } + } + let result = Self { + keys0, + joiner, + keys1, + values, + }; + // In debug mode, check the optional invariants, too + #[cfg(debug_assertions)] + result.check_invariants(); + Ok(result) + } + } +} + +/// This impl can be made available by enabling the optional `serde` feature of the `zerovec` crate +impl<'de, 'a, K0, K1, V> Deserialize<'de> for ZeroMap2dBorrowed<'a, K0, K1, V> +where + K0: ZeroMapKV<'a> + Ord + ?Sized, + K1: ZeroMapKV<'a> + Ord + ?Sized, + V: ZeroMapKV<'a> + ?Sized, + K0::Container: Deserialize<'de>, + K1::Container: Deserialize<'de>, + V::Container: Deserialize<'de>, + K0::OwnedType: Deserialize<'de>, + K1::OwnedType: Deserialize<'de>, + V::OwnedType: Deserialize<'de>, + 'de: 'a, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + Err(de::Error::custom( + "ZeroMap2dBorrowed cannot be deserialized from human-readable formats", + )) + } else { + let deserialized: ZeroMap2d<'a, K0, K1, V> = ZeroMap2d::deserialize(deserializer)?; + let keys0 = if let Some(keys0) = deserialized.keys0.zvl_as_borrowed_inner() { + keys0 + } else { + return Err(de::Error::custom( + "ZeroMap2dBorrowed can only deserialize in zero-copy ways", + )); + }; + let joiner = if let Some(joiner) = deserialized.joiner.zvl_as_borrowed_inner() { + joiner + } else { + return Err(de::Error::custom( + "ZeroMap2dBorrowed can only deserialize in zero-copy ways", + )); + }; + let keys1 = if let Some(keys1) = deserialized.keys1.zvl_as_borrowed_inner() { + keys1 + } else { + return Err(de::Error::custom( + "ZeroMap2dBorrowed can only deserialize in zero-copy ways", + )); + }; + let values = if let Some(values) = deserialized.values.zvl_as_borrowed_inner() { + values + } else { + return Err(de::Error::custom( + "ZeroMap2dBorrowed can only deserialize in zero-copy ways", + )); + }; + Ok(Self { + keys0, + joiner, + keys1, + values, + }) + } + } +} + +#[cfg(test)] +#[allow(non_camel_case_types)] +mod test { + use crate::map2d::{ZeroMap2d, ZeroMap2dBorrowed}; + + #[derive(serde::Serialize, serde::Deserialize)] + struct DeriveTest_ZeroMap2d<'data> { + #[serde(borrow)] + _data: ZeroMap2d<'data, u16, str, [u8]>, + } + + #[derive(serde::Serialize, serde::Deserialize)] + struct DeriveTest_ZeroMap2dBorrowed<'data> { + #[serde(borrow)] + _data: ZeroMap2dBorrowed<'data, u16, str, [u8]>, + } + + const JSON_STR: &str = "{\"1\":{\"1\":\"uno\"},\"2\":{\"2\":\"dos\",\"3\":\"tres\"}}"; + const BINCODE_BYTES: &[u8] = &[ + 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, + 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, + 3, 0, 6, 0, 117, 110, 111, 100, 111, 115, 116, 114, 101, 115, + ]; + + fn make_map() -> ZeroMap2d<'static, u32, u16, str> { + let mut map = ZeroMap2d::new(); + map.insert(&1, &1, "uno"); + map.insert(&2, &2, "dos"); + map.insert(&2, &3, "tres"); + map + } + + #[test] + fn test_serde_json() { + let map = make_map(); + let json_str = serde_json::to_string(&map).expect("serialize"); + assert_eq!(JSON_STR, json_str); + let new_map: ZeroMap2d<u32, u16, str> = + serde_json::from_str(&json_str).expect("deserialize"); + assert_eq!(format!("{:?}", new_map), format!("{:?}", map)); + } + + #[test] + fn test_bincode() { + let map = make_map(); + let bincode_bytes = bincode::serialize(&map).expect("serialize"); + assert_eq!(BINCODE_BYTES, bincode_bytes); + let new_map: ZeroMap2d<u32, u16, str> = + bincode::deserialize(&bincode_bytes).expect("deserialize"); + assert_eq!( + format!("{:?}", new_map), + format!("{:?}", map).replace("Owned", "Borrowed"), + ); + + let new_map: ZeroMap2dBorrowed<u32, u16, str> = + bincode::deserialize(&bincode_bytes).expect("deserialize"); + assert_eq!( + format!("{:?}", new_map), + format!("{:?}", map) + .replace("Owned", "Borrowed") + .replace("ZeroMap2d", "ZeroMap2dBorrowed") + ); + } + + #[test] + fn test_sample_bincode() { + // This is the map from the main docs page for ZeroMap2d + let mut map: ZeroMap2d<u16, u16, str> = ZeroMap2d::new(); + map.insert(&1, &2, "three"); + let bincode_bytes: Vec<u8> = bincode::serialize(&map).expect("serialize"); + assert_eq!( + bincode_bytes.as_slice(), + &[ + 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, + 0, 0, 2, 0, 11, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 116, 104, 114, 101, 101 + ] + ); + } +} |