summaryrefslogtreecommitdiffstats
path: root/vendor/zerovec/src/map2d/serde.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/zerovec/src/map2d/serde.rs')
-rw-r--r--vendor/zerovec/src/map2d/serde.rs430
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
+ ]
+ );
+ }
+}