// 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::{VarZeroSlice, VarZeroVec, VarZeroVecFormat}; use crate::ule::*; use alloc::boxed::Box; use alloc::vec::Vec; use core::fmt; use core::marker::PhantomData; use serde::de::{self, Deserialize, Deserializer, SeqAccess, Visitor}; #[cfg(feature = "serde")] use serde::ser::{Serialize, SerializeSeq, Serializer}; struct VarZeroVecVisitor { #[allow(clippy::type_complexity)] // this is a private marker type, who cares marker: PhantomData<(fn() -> Box, F)>, } impl Default for VarZeroVecVisitor { fn default() -> Self { Self { marker: PhantomData, } } } impl<'de, T, F> Visitor<'de> for VarZeroVecVisitor where T: VarULE + ?Sized, Box: Deserialize<'de>, F: VarZeroVecFormat, { type Value = VarZeroVec<'de, T, F>; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence or borrowed buffer of bytes") } fn visit_borrowed_bytes(self, bytes: &'de [u8]) -> Result where E: de::Error, { VarZeroVec::parse_byte_slice(bytes).map_err(de::Error::custom) } fn visit_seq(self, mut seq: A) -> Result where A: SeqAccess<'de>, { let mut vec: Vec> = if let Some(capacity) = seq.size_hint() { Vec::with_capacity(capacity) } else { Vec::new() }; while let Some(value) = seq.next_element::>()? { vec.push(value); } Ok(VarZeroVec::from(&vec)) } } /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate impl<'de, 'a, T, F> Deserialize<'de> for VarZeroVec<'a, T, F> where T: VarULE + ?Sized, Box: Deserialize<'de>, F: VarZeroVecFormat, 'de: 'a, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let visitor = VarZeroVecVisitor::default(); if deserializer.is_human_readable() { deserializer.deserialize_seq(visitor) } else { deserializer.deserialize_bytes(visitor) } } } /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate impl<'de, 'a, T, F> Deserialize<'de> for &'a VarZeroSlice where T: VarULE + ?Sized, Box: Deserialize<'de>, F: VarZeroVecFormat, 'de: 'a, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { Err(de::Error::custom( "&VarZeroSlice cannot be deserialized from human-readable formats", )) } else { let deserialized: VarZeroVec<'a, T, F> = VarZeroVec::deserialize(deserializer)?; let borrowed = if let VarZeroVec::Borrowed(b) = deserialized { b } else { return Err(de::Error::custom( "&VarZeroSlice can only deserialize in zero-copy ways", )); }; Ok(borrowed) } } } /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate #[cfg(feature = "serde")] impl Serialize for VarZeroVec<'_, T, F> where T: Serialize + VarULE + ?Sized, F: VarZeroVecFormat, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { if serializer.is_human_readable() { let mut seq = serializer.serialize_seq(Some(self.len()))?; for value in self.iter() { seq.serialize_element(value)?; } seq.end() } else { serializer.serialize_bytes(self.as_bytes()) } } } /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate #[cfg(feature = "serde")] impl Serialize for VarZeroSlice where T: Serialize + VarULE + ?Sized, F: VarZeroVecFormat, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.as_varzerovec().serialize(serializer) } } #[cfg(test)] #[allow(non_camel_case_types)] mod test { use crate::{VarZeroSlice, VarZeroVec}; #[derive(serde::Serialize, serde::Deserialize)] struct DeriveTest_VarZeroVec<'data> { #[serde(borrow)] _data: VarZeroVec<'data, str>, } #[derive(serde::Serialize, serde::Deserialize)] struct DeriveTest_VarZeroSlice<'data> { #[serde(borrow)] _data: &'data VarZeroSlice, } // ["foo", "bar", "baz", "dolor", "quux", "lorem ipsum"]; const BYTES: &[u8] = &[ 6, 0, 0, 0, 0, 0, 3, 0, 6, 0, 9, 0, 14, 0, 18, 0, 102, 111, 111, 98, 97, 114, 98, 97, 122, 100, 111, 108, 111, 114, 113, 117, 117, 120, 108, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, ]; const JSON_STR: &str = "[\"foo\",\"bar\",\"baz\",\"dolor\",\"quux\",\"lorem ipsum\"]"; const BINCODE_BUF: &[u8] = &[ 45, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 3, 0, 6, 0, 9, 0, 14, 0, 18, 0, 102, 111, 111, 98, 97, 114, 98, 97, 122, 100, 111, 108, 111, 114, 113, 117, 117, 120, 108, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, ]; // ["w", "ω", "文", "𑄃"] const NONASCII_STR: &[&str] = &["w", "ω", "文", "𑄃"]; const NONASCII_BYTES: &[u8] = &[ 4, 0, 0, 0, 0, 0, 1, 0, 3, 0, 6, 0, 119, 207, 137, 230, 150, 135, 240, 145, 132, 131, ]; #[test] fn test_serde_json() { let zerovec_orig: VarZeroVec = VarZeroVec::parse_byte_slice(BYTES).expect("parse"); let json_str = serde_json::to_string(&zerovec_orig).expect("serialize"); assert_eq!(JSON_STR, json_str); // VarZeroVec should deserialize from JSON to either Vec or VarZeroVec let vec_new: Vec> = serde_json::from_str(&json_str).expect("deserialize from buffer to Vec"); assert_eq!(zerovec_orig.to_vec(), vec_new); let zerovec_new: VarZeroVec = serde_json::from_str(&json_str).expect("deserialize from buffer to VarZeroVec"); assert_eq!(zerovec_orig.to_vec(), zerovec_new.to_vec()); assert!(zerovec_new.is_owned()); } #[test] fn test_serde_bincode() { let zerovec_orig: VarZeroVec = VarZeroVec::parse_byte_slice(BYTES).expect("parse"); let bincode_buf = bincode::serialize(&zerovec_orig).expect("serialize"); assert_eq!(BINCODE_BUF, bincode_buf); let zerovec_new: VarZeroVec = bincode::deserialize(&bincode_buf).expect("deserialize from buffer to VarZeroVec"); assert_eq!(zerovec_orig.to_vec(), zerovec_new.to_vec()); assert!(!zerovec_new.is_owned()); } #[test] fn test_vzv_borrowed() { let zerovec_orig: &VarZeroSlice = VarZeroSlice::parse_byte_slice(BYTES).expect("parse"); let bincode_buf = bincode::serialize(&zerovec_orig).expect("serialize"); assert_eq!(BINCODE_BUF, bincode_buf); let zerovec_new: &VarZeroSlice = bincode::deserialize(&bincode_buf).expect("deserialize from buffer to VarZeroSlice"); assert_eq!(zerovec_orig.to_vec(), zerovec_new.to_vec()); } #[test] fn test_nonascii_bincode() { let src_vec = NONASCII_STR .iter() .copied() .map(Box::::from) .collect::>(); let mut zerovec: VarZeroVec = VarZeroVec::parse_byte_slice(NONASCII_BYTES).expect("parse"); assert_eq!(zerovec.to_vec(), src_vec); let bincode_buf = bincode::serialize(&zerovec).expect("serialize"); let zerovec_result = bincode::deserialize::>(&bincode_buf).expect("deserialize"); assert_eq!(zerovec_result.to_vec(), src_vec); // try again with owned zerovec zerovec.make_mut(); let bincode_buf = bincode::serialize(&zerovec).expect("serialize"); let zerovec_result = bincode::deserialize::>(&bincode_buf).expect("deserialize"); assert_eq!(zerovec_result.to_vec(), src_vec); } }