// 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::{ZeroSlice, ZeroVec}; use crate::ule::*; use alloc::boxed::Box; use alloc::vec::Vec; use core::fmt; use core::marker::PhantomData; use core::mem; use serde::de::{self, Deserialize, Deserializer, SeqAccess, Visitor}; #[cfg(feature = "serde")] use serde::ser::{Serialize, SerializeSeq, Serializer}; struct ZeroVecVisitor { marker: PhantomData T>, } impl Default for ZeroVecVisitor { fn default() -> Self { Self { marker: PhantomData, } } } impl<'de, T> Visitor<'de> for ZeroVecVisitor where T: 'de + Deserialize<'de> + AsULE, { type Value = ZeroVec<'de, T>; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence or borrowed buffer of fixed-width elements") } fn visit_borrowed_bytes(self, bytes: &'de [u8]) -> Result where E: de::Error, { ZeroVec::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(T::to_unaligned(value)); } Ok(ZeroVec::new_owned(vec)) } } /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate impl<'de, 'a, T> Deserialize<'de> for ZeroVec<'a, T> where T: 'de + Deserialize<'de> + AsULE, 'de: 'a, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let visitor = ZeroVecVisitor::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 Serialize for ZeroVec<'_, T> where T: Serialize + AsULE, { 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 impl<'de, T> Deserialize<'de> for Box> where T: Deserialize<'de> + AsULE + 'static, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let mut zv = ZeroVec::::deserialize(deserializer)?; let vec = zv.with_mut(mem::take); Ok(ZeroSlice::from_boxed_slice(vec.into_boxed_slice())) } } /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate impl<'de, 'a, T> Deserialize<'de> for &'a ZeroSlice where T: Deserialize<'de> + AsULE + 'static, 'de: 'a, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { Err(de::Error::custom( "&ZeroSlice cannot be deserialized from human-readable formats", )) } else { let deserialized: ZeroVec<'a, T> = ZeroVec::deserialize(deserializer)?; let borrowed = if let Some(b) = deserialized.as_maybe_borrowed() { b } else { return Err(de::Error::custom( "&ZeroSlice can only deserialize in zero-copy ways", )); }; Ok(borrowed) } } } /// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate impl Serialize for ZeroSlice where T: Serialize + AsULE, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.as_zerovec().serialize(serializer) } } #[cfg(test)] #[allow(non_camel_case_types)] mod test { use crate::samples::*; use crate::ZeroVec; #[derive(serde::Serialize, serde::Deserialize)] struct DeriveTest_ZeroVec<'data> { #[serde(borrow)] _data: ZeroVec<'data, u16>, } #[test] fn test_serde_json() { let zerovec_orig = ZeroVec::from_slice_or_alloc(TEST_SLICE); let json_str = serde_json::to_string(&zerovec_orig).expect("serialize"); assert_eq!(JSON_STR, json_str); // ZeroVec should deserialize from JSON to either Vec or ZeroVec let vec_new: Vec = serde_json::from_str(&json_str).expect("deserialize from buffer to Vec"); assert_eq!( zerovec_orig, ZeroVec::::from_slice_or_alloc(vec_new.as_slice()) ); let zerovec_new: ZeroVec = serde_json::from_str(&json_str).expect("deserialize from buffer to ZeroVec"); assert_eq!(zerovec_orig, zerovec_new); assert!(zerovec_new.is_owned()); } #[test] fn test_serde_bincode() { let zerovec_orig = ZeroVec::from_slice_or_alloc(TEST_SLICE); let bincode_buf = bincode::serialize(&zerovec_orig).expect("serialize"); assert_eq!(BINCODE_BUF, bincode_buf); // ZeroVec should deserialize from Bincode to ZeroVec but not Vec bincode::deserialize::>(&bincode_buf).expect_err("deserialize from buffer to Vec"); let zerovec_new: ZeroVec = bincode::deserialize(&bincode_buf).expect("deserialize from buffer to ZeroVec"); assert_eq!(zerovec_orig, zerovec_new); assert!(!zerovec_new.is_owned()); } #[test] fn test_chars_valid() { // 1-byte, 2-byte, 3-byte, and 4-byte character in UTF-8 (not as relevant in UTF-32) let zerovec_orig = ZeroVec::alloc_from_slice(&['w', 'ω', '文', '𑄃']); let bincode_buf = bincode::serialize(&zerovec_orig).expect("serialize"); let zerovec_new: ZeroVec = bincode::deserialize(&bincode_buf).expect("deserialize from buffer to ZeroVec"); assert_eq!(zerovec_orig, zerovec_new); assert!(!zerovec_new.is_owned()); } #[test] fn test_chars_invalid() { // 119 and 120 are valid, but not 0xD800 (high surrogate) let zerovec_orig: ZeroVec = ZeroVec::from_slice_or_alloc(&[119, 0xD800, 120]); let bincode_buf = bincode::serialize(&zerovec_orig).expect("serialize"); let zerovec_result = bincode::deserialize::>(&bincode_buf); assert!(matches!(zerovec_result, Err(_))); } }