| // 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<T> { |
| marker: PhantomData<fn() -> T>, |
| } |
| |
| impl<T> Default for ZeroVecVisitor<T> { |
| fn default() -> Self { |
| Self { |
| marker: PhantomData, |
| } |
| } |
| } |
| |
| impl<'de, T> Visitor<'de> for ZeroVecVisitor<T> |
| 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<E>(self, bytes: &'de [u8]) -> Result<Self::Value, E> |
| where |
| E: de::Error, |
| { |
| ZeroVec::parse_byte_slice(bytes).map_err(de::Error::custom) |
| } |
| |
| fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> |
| where |
| A: SeqAccess<'de>, |
| { |
| let mut vec: Vec<T::ULE> = if let Some(capacity) = seq.size_hint() { |
| Vec::with_capacity(capacity) |
| } else { |
| Vec::new() |
| }; |
| while let Some(value) = seq.next_element::<T>()? { |
| 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<D>(deserializer: D) -> Result<Self, D::Error> |
| 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<T> Serialize for ZeroVec<'_, T> |
| where |
| T: Serialize + AsULE, |
| { |
| fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 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<ZeroSlice<T>> |
| where |
| T: Deserialize<'de> + AsULE + 'static, |
| { |
| fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| where |
| D: Deserializer<'de>, |
| { |
| let mut zv = ZeroVec::<T>::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<T> |
| where |
| T: Deserialize<'de> + AsULE + 'static, |
| 'de: 'a, |
| { |
| fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| 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<T> Serialize for ZeroSlice<T> |
| where |
| T: Serialize + AsULE, |
| { |
| fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 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<u32> = |
| serde_json::from_str(&json_str).expect("deserialize from buffer to Vec"); |
| assert_eq!( |
| zerovec_orig, |
| ZeroVec::<u32>::from_slice_or_alloc(vec_new.as_slice()) |
| ); |
| let zerovec_new: ZeroVec<u32> = |
| 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::<Vec<u32>>(&bincode_buf).expect_err("deserialize from buffer to Vec"); |
| let zerovec_new: ZeroVec<u32> = |
| 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<char> = |
| 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<u32> = ZeroVec::from_slice_or_alloc(&[119, 0xD800, 120]); |
| let bincode_buf = bincode::serialize(&zerovec_orig).expect("serialize"); |
| let zerovec_result = bincode::deserialize::<ZeroVec<char>>(&bincode_buf); |
| assert!(zerovec_result.is_err()); |
| } |
| } |