From 737a9153d2563200f06d2866c846dd22075fa7e2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 10 Jun 2020 20:04:02 -0700 Subject: [PATCH 1/2] Allow deserializing Cow<[u8]> to produce owned bytes --- src/de.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/src/de.rs b/src/de.rs index eb60618..719a983 100644 --- a/src/de.rs +++ b/src/de.rs @@ -7,6 +7,9 @@ use serde::Deserializer; #[cfg(any(feature = "std", feature = "alloc"))] use crate::ByteBuf; +#[cfg(any(feature = "std", feature = "alloc"))] +use core::cmp; + #[cfg(feature = "alloc")] use alloc::borrow::Cow; #[cfg(all(feature = "std", not(feature = "alloc")))] @@ -14,10 +17,14 @@ use std::borrow::Cow; #[cfg(feature = "alloc")] use alloc::boxed::Box; - +#[cfg(feature = "alloc")] +use alloc::string::String; #[cfg(feature = "alloc")] use alloc::vec::Vec; +#[cfg(any(feature = "std", feature = "alloc"))] +use serde::de::SeqAccess; + /// Types that can be deserialized via `#[serde(with = "serde_bytes")]`. pub trait Deserialize<'de>: Sized { #[allow(missing_docs)] @@ -72,7 +79,73 @@ impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> { where D: Deserializer<'de>, { - Deserialize::deserialize(deserializer).map(Cow::Borrowed) + struct CowVisitor; + + impl<'de> Visitor<'de> for CowVisitor { + type Value = Cow<'de, [u8]>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a byte array") + } + + fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result + where + E: Error, + { + Ok(Cow::Borrowed(v)) + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: Error, + { + Ok(Cow::Borrowed(v.as_bytes())) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + Ok(Cow::Owned(v.to_vec())) + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(Cow::Owned(v.as_bytes().to_vec())) + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + Ok(Cow::Owned(v)) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + Ok(Cow::Owned(v.into_bytes())) + } + + fn visit_seq(self, mut visitor: V) -> Result + where + V: SeqAccess<'de>, + { + let len = cmp::min(visitor.size_hint().unwrap_or(0), 4096); + let mut bytes = Vec::with_capacity(len); + + while let Some(b) = visitor.next_element()? { + bytes.push(b); + } + + Ok(Cow::Owned(bytes)) + } + } + + deserializer.deserialize_bytes(CowVisitor) } } From 0ed0ae616a1ce07fcfe3ec1626d982de62821364 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 10 Jun 2020 20:07:20 -0700 Subject: [PATCH 2/2] Forward Cow de impl to Cow<[u8]> --- src/de.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/de.rs b/src/de.rs index 719a983..d3aa8e1 100644 --- a/src/de.rs +++ b/src/de.rs @@ -155,7 +155,11 @@ impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, Bytes> { where D: Deserializer<'de>, { - Deserialize::deserialize(deserializer).map(Cow::Borrowed) + let cow: Cow<[u8]> = Deserialize::deserialize(deserializer)?; + match cow { + Cow::Borrowed(bytes) => Ok(Cow::Borrowed(Bytes::new(bytes))), + Cow::Owned(bytes) => Ok(Cow::Owned(ByteBuf::from(bytes))), + } } }