diff options
Diffstat (limited to 'vendor/zerovec/src/varzerovec/serde.rs')
-rw-r--r-- | vendor/zerovec/src/varzerovec/serde.rs | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/vendor/zerovec/src/varzerovec/serde.rs b/vendor/zerovec/src/varzerovec/serde.rs new file mode 100644 index 000000000..dd6e863ff --- /dev/null +++ b/vendor/zerovec/src/varzerovec/serde.rs @@ -0,0 +1,246 @@ +// 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<T: ?Sized, F: VarZeroVecFormat> { + #[allow(clippy::type_complexity)] // this is a private marker type, who cares + marker: PhantomData<(fn() -> Box<T>, F)>, +} + +impl<T: ?Sized, F: VarZeroVecFormat> Default for VarZeroVecVisitor<T, F> { + fn default() -> Self { + Self { + marker: PhantomData, + } + } +} + +impl<'de, T, F> Visitor<'de> for VarZeroVecVisitor<T, F> +where + T: VarULE + ?Sized, + Box<T>: 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<E>(self, bytes: &'de [u8]) -> Result<Self::Value, E> + where + E: de::Error, + { + VarZeroVec::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<Box<T>> = if let Some(capacity) = seq.size_hint() { + Vec::with_capacity(capacity) + } else { + Vec::new() + }; + while let Some(value) = seq.next_element::<Box<T>>()? { + vec.push(value); + } + Ok(VarZeroVec::from(&vec)) + } +} + +/// This impl can be made available by enabling the optional `serde` feature of the `zerovec` crate +impl<'de, 'a, T, F> Deserialize<'de> for VarZeroVec<'a, T, F> +where + T: VarULE + ?Sized, + Box<T>: Deserialize<'de>, + F: VarZeroVecFormat, + 'de: 'a, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + let visitor = VarZeroVecVisitor::default(); + if deserializer.is_human_readable() { + deserializer.deserialize_seq(visitor) + } else { + deserializer.deserialize_bytes(visitor) + } + } +} + +/// This impl can be made available by enabling the optional `serde` feature of the `zerovec` crate +impl<'de, 'a, T, F> Deserialize<'de> for &'a VarZeroSlice<T, F> +where + T: VarULE + ?Sized, + Box<T>: Deserialize<'de>, + F: VarZeroVecFormat, + 'de: 'a, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + 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 can be made available by enabling the optional `serde` feature of the `zerovec` crate +#[cfg(feature = "serde")] +impl<T, F> Serialize for VarZeroVec<'_, T, F> +where + T: Serialize + VarULE + ?Sized, + F: VarZeroVecFormat, +{ + 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 can be made available by enabling the optional `serde` feature of the `zerovec` crate +#[cfg(feature = "serde")] +impl<T, F> Serialize for VarZeroSlice<T, F> +where + T: Serialize + VarULE + ?Sized, + F: VarZeroVecFormat, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + 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<str>, + } + + // ["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<str> = 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<Box<str>> = + serde_json::from_str(&json_str).expect("deserialize from buffer to Vec"); + assert_eq!(zerovec_orig.to_vec(), vec_new); + let zerovec_new: VarZeroVec<str> = + 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<str> = 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<str> = + 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<str> = + 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<str> = + 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::<str>::from) + .collect::<Vec<_>>(); + let mut zerovec: VarZeroVec<str> = + 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::<VarZeroVec<str>>(&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::<VarZeroVec<str>>(&bincode_buf).expect("deserialize"); + assert_eq!(zerovec_result.to_vec(), src_vec); + } +} |