Skip to content

Commit

Permalink
Support Deserialization for VarZeroVec<VarZeroSlice> (#3643)
Browse files Browse the repository at this point in the history
  • Loading branch information
skius authored Jul 7, 2023
1 parent 1c59637 commit b2a1b79
Showing 1 changed file with 113 additions and 11 deletions.
124 changes: 113 additions & 11 deletions utils/zerovec/src/varzerovec/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,32 @@ impl<T: ?Sized, F: VarZeroVecFormat> Default for VarZeroVecVisitor<T, F> {
}
}

struct VarZeroSliceBoxVisitor<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 VarZeroSliceBoxVisitor<T, F> {
fn default() -> Self {
Self {
marker: PhantomData,
}
}
}

struct VarZeroSliceRefVisitor<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 VarZeroSliceRefVisitor<T, F> {
fn default() -> Self {
Self {
marker: PhantomData,
}
}
}

impl<'de, T, F> Visitor<'de> for VarZeroVecVisitor<T, F>
where
T: VarULE + ?Sized,
Expand Down Expand Up @@ -60,6 +86,62 @@ where
}
}

impl<'de, T, F> Visitor<'de> for VarZeroSliceBoxVisitor<T, F>
where
T: VarULE + ?Sized,
Box<T>: Deserialize<'de>,
F: VarZeroVecFormat,
{
type Value = Box<VarZeroSlice<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,
{
VarZeroSlice::parse_byte_slice(bytes)
.map(VarULE::to_boxed)
.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).to_boxed())
}
}

impl<'de, T, F> Visitor<'de> for VarZeroSliceRefVisitor<T, F>
where
T: VarULE + ?Sized,
F: VarZeroVecFormat,
{
type Value = &'de VarZeroSlice<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,
{
VarZeroSlice::parse_byte_slice(bytes).map_err(de::Error::custom)
}
}

/// 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
Expand All @@ -72,7 +154,7 @@ where
where
D: Deserializer<'de>,
{
let visitor = VarZeroVecVisitor::default();
let visitor: VarZeroVecVisitor<T, F> = VarZeroVecVisitor::default();
if deserializer.is_human_readable() {
deserializer.deserialize_seq(visitor)
} else {
Expand All @@ -85,7 +167,6 @@ where
impl<'de, 'a, T, F> Deserialize<'de> for &'a VarZeroSlice<T, F>
where
T: VarULE + ?Sized,
Box<T>: Deserialize<'de>,
F: VarZeroVecFormat,
'de: 'a,
{
Expand All @@ -98,15 +179,30 @@ where
"&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)
let visitor: VarZeroSliceRefVisitor<T, F> = VarZeroSliceRefVisitor::default();
let deserialized: &'a VarZeroSlice<_, _> = deserializer.deserialize_bytes(visitor)?;
Ok(deserialized)
}
}
}

/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
impl<'de, 'a, T, F> Deserialize<'de> for Box<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>,
{
let visitor: VarZeroSliceBoxVisitor<T, F> = VarZeroSliceBoxVisitor::default();
if deserializer.is_human_readable() {
deserializer.deserialize_seq(visitor)
} else {
deserializer.deserialize_bytes(visitor)
}
}
}
Expand Down Expand Up @@ -160,6 +256,12 @@ mod test {
_data: VarZeroVec<'data, str>,
}

#[derive(serde::Serialize, serde::Deserialize)]
struct DeriveTest_VarZeroVec_of_VarZeroSlice<'data> {
#[serde(borrow)]
_data: VarZeroVec<'data, VarZeroSlice<str>>,
}

#[derive(serde::Serialize, serde::Deserialize)]
struct DeriveTest_VarZeroSlice<'data> {
#[serde(borrow)]
Expand Down

0 comments on commit b2a1b79

Please sign in to comment.