blob: bb180d5a19bb529f019a0c49ed173f0d937a851d [file] [log] [blame]
// 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());
}
}