// 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::ZeroHashMap; use crate::{ map::{ZeroMapKV, ZeroVecLike}, ZeroVec, }; use serde::{de, Deserialize, Serialize}; impl<'a, K, V> Serialize for ZeroHashMap<'a, K, V> where K: ZeroMapKV<'a> + Serialize + ?Sized, V: ZeroMapKV<'a> + Serialize + ?Sized, K::Container: Serialize, V::Container: Serialize, { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { (&self.displacements, &self.keys, &self.values).serialize(serializer) } } impl<'de, 'a, K, V> Deserialize<'de> for ZeroHashMap<'a, K, V> where K: ZeroMapKV<'a> + ?Sized, V: ZeroMapKV<'a> + ?Sized, K::Container: Deserialize<'de>, V::Container: Deserialize<'de>, 'de: 'a, { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let (displacements, keys, values): (ZeroVec<(u32, u32)>, K::Container, V::Container) = Deserialize::deserialize(deserializer)?; if keys.zvl_len() != values.zvl_len() { return Err(de::Error::custom( "Mismatched key and value sizes in ZeroHashMap", )); } if displacements.zvl_len() != keys.zvl_len() { return Err(de::Error::custom( "Mismatched displacements and key, value sizes in ZeroHashMap", )); } Ok(Self { displacements, keys, values, }) } } #[cfg(test)] mod test { use crate::{VarZeroVec, ZeroHashMap, ZeroVec}; use serde::{Deserialize, Serialize}; const JSON_STR: &str = "[[[0,1],[0,0],[0,1]],[2,1,0],[\"c\",\"b\",\"a\"]]"; const BINCODE_BYTES: &[u8] = &[ 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 0, 2, 0, 99, 98, 97, ]; #[derive(Serialize, Deserialize)] struct DeriveTestZeroHashMap<'data> { #[serde(borrow)] _data: ZeroHashMap<'data, str, [u8]>, } fn make_zerohashmap() -> ZeroHashMap<'static, u32, str> { ZeroHashMap::from_iter(vec![(0, "a"), (1, "b"), (2, "c")].into_iter()) } fn build_invalid_hashmap_str( displacements: Vec<(u32, u32)>, keys: Vec, values: Vec<&str>, ) -> String { let invalid_hm: ZeroHashMap = ZeroHashMap { displacements: ZeroVec::alloc_from_slice(&displacements), keys: ZeroVec::alloc_from_slice(&keys), values: VarZeroVec::::from(&values), }; serde_json::to_string(&invalid_hm).expect("serialize") } #[test] fn test_invalid_deser_zhm() { // Invalid hashmap |keys| != |values| let mut invalid_hm_str = build_invalid_hashmap_str(vec![(0, 1), (0, 0)], vec![1, 2], vec!["a", "b", "c"]); assert_eq!( serde_json::from_str::>(&invalid_hm_str) .unwrap_err() .to_string(), "Mismatched key and value sizes in ZeroHashMap" ); // Invalid hashmap |displacements| != |keys| == |values| // |displacements| = 2, |keys| = 3, |values| = 3 invalid_hm_str = build_invalid_hashmap_str(vec![(0, 1), (0, 0)], vec![2, 1, 0], vec!["a", "b", "c"]); assert_eq!( serde_json::from_str::>(&invalid_hm_str) .unwrap_err() .to_string(), "Mismatched displacements and key, value sizes in ZeroHashMap" ); } #[test] fn test_serde_valid_deser_zhm() { let hm = make_zerohashmap(); let json_str = serde_json::to_string(&hm).expect("serialize"); assert_eq!(json_str, JSON_STR); let deserialized_hm: ZeroHashMap = serde_json::from_str(JSON_STR).expect("deserialize"); assert_eq!( hm.iter().collect::>(), deserialized_hm.iter().collect::>() ); } #[test] fn test_bincode_zhm() { let hm = make_zerohashmap(); let bincode_bytes = bincode::serialize(&hm).expect("serialize"); assert_eq!(bincode_bytes, BINCODE_BYTES); let deserialized_hm: ZeroHashMap = bincode::deserialize(BINCODE_BYTES).expect("deserialize"); assert_eq!( hm.iter().collect::>(), deserialized_hm.iter().collect::>() ); } }