Source code
Revision control
Copy as Markdown
Other Tools
// 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
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 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<T>: Deserialize<'de>,
F: VarZeroVecFormat,
'de: 'a,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let visitor = VarZeroVecVisitor::<T, F>::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<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>::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
impl<'de, T, F> Deserialize<'de> for Box<VarZeroSlice<T, F>>
where
T: VarULE + ?Sized,
Box<T>: Deserialize<'de>,
F: VarZeroVecFormat,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let deserialized = VarZeroVec::<T, F>::deserialize(deserializer)?;
Ok(deserialized.to_boxed())
}
}
/// This impl requires enabling the optional `serde` Cargo 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 requires enabling the optional `serde` Cargo 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>,
}
#[derive(serde::Serialize, serde::Deserialize)]
struct DeriveTest_VarZeroVec_of_VarZeroSlice<'data> {
#[serde(borrow)]
_data: VarZeroVec<'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);
}
}