Merge pull request 1917 from Mingun/borrow-identifier

This commit is contained in:
David Tolnay 2021-01-23 12:20:18 -08:00
commit ba46f45dc5
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
6 changed files with 238 additions and 146 deletions

View File

@ -116,6 +116,7 @@ use lib::*;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#[macro_use]
pub mod value; pub mod value;
mod from_primitive; mod from_primitive;

View File

@ -30,8 +30,10 @@ use ser;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// For structs that contain a PhantomData. We do not want the trait /// For structs that contain a PhantomData. We do not want the trait
// bound `E: Clone` inferred by derive(Clone). /// bound `E: Clone` inferred by derive(Clone).
#[doc(hidden)]
#[macro_export]
macro_rules! impl_copy_clone { macro_rules! impl_copy_clone {
($ty:ident $(<$lifetime:tt>)*) => { ($ty:ident $(<$lifetime:tt>)*) => {
impl<$($lifetime,)* E> Copy for $ty<$($lifetime,)* E> {} impl<$($lifetime,)* E> Copy for $ty<$($lifetime,)* E> {}
@ -44,6 +46,102 @@ macro_rules! impl_copy_clone {
}; };
} }
/// Creates a deserializer any method of which forwards to the specified visitor method
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! forward_deserializer {
// Non-borrowed references
(
$(#[$doc:meta])*
// Actually, * in lifetime should be ?, but that syntax is not supported
// on old Rust versions (<= 1.28) or in 2015 edition
ref $deserializer:ident $(<$lifetime:tt>)* ($ty:ty) => $visit:ident
) => {
$(#[$doc])*
#[derive(Debug)]
pub struct $deserializer<$($lifetime,)* E> {
value: $ty,
marker: PhantomData<E>,
}
impl<$($lifetime,)* E> $deserializer<$($lifetime,)* E> {
/// Create a new deserializer from the given value.
pub fn new(value: $ty) -> Self {
$deserializer {
value: value,
marker: PhantomData,
}
}
}
impl_copy_clone!($deserializer $(<$lifetime>)*);
impl<'de, $($lifetime,)* E> $crate::de::Deserializer<'de> for $deserializer<$($lifetime,)* E>
where
E: $crate::de::Error,
{
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> $crate::export::Result<V::Value, Self::Error>
where
V: $crate::de::Visitor<'de>,
{
visitor.$visit(self.value)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str
string bytes byte_buf option unit unit_struct newtype_struct seq
tuple tuple_struct map struct enum identifier ignored_any
}
}
};
// Borrowed references
(
$(#[$doc:meta])*
borrowed $deserializer:ident($ty:ty) => $visit:ident
) => {
$(#[$doc])*
#[derive(Debug)]
pub struct $deserializer<'de, E> {
value: $ty,
marker: PhantomData<E>,
}
impl<'de, E> $deserializer<'de, E> {
/// Create a new borrowed deserializer from the given value.
pub fn new(value: $ty) -> Self {
$deserializer {
value: value,
marker: PhantomData,
}
}
}
impl_copy_clone!($deserializer<'de>);
impl<'de, E> $crate::de::Deserializer<'de> for $deserializer<'de, E>
where
E: $crate::de::Error,
{
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> $crate::export::Result<V::Value, Self::Error>
where
V: $crate::de::Visitor<'de>,
{
visitor.$visit(self.value)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str
string bytes byte_buf option unit unit_struct newtype_struct seq
tuple tuple_struct map struct enum identifier ignored_any
}
}
};
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// A minimal representation of all possible errors that can occur using the /// A minimal representation of all possible errors that can occur using the
@ -665,45 +763,19 @@ where
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// A deserializer holding a `&[u8]` with a lifetime tied to another forward_deserializer!(
/// deserializer. /// A deserializer holding a `&[u8]`. Always call [`Visitor::visit_bytes`]
#[derive(Debug)] ///
pub struct BorrowedBytesDeserializer<'de, E> { /// [`Visitor::visit_bytes`]: ../struct.Visitor.html#method.visit_bytes
value: &'de [u8], ref BytesDeserializer<'a>(&'a [u8]) => visit_bytes
marker: PhantomData<E>, );
} forward_deserializer!(
/// A deserializer holding a `&[u8]` with a lifetime tied to another
impl_copy_clone!(BorrowedBytesDeserializer<'de>); /// deserializer. Always call [`Visitor::visit_borrowed_bytes`]
///
impl<'de, E> BorrowedBytesDeserializer<'de, E> { /// [`Visitor::visit_borrowed_bytes`]: ../struct.Visitor.html#method.visit_borrowed_bytes
/// Create a new borrowed deserializer from the given byte slice. borrowed BorrowedBytesDeserializer(&'de [u8]) => visit_borrowed_bytes
pub fn new(value: &'de [u8]) -> BorrowedBytesDeserializer<'de, E> { );
BorrowedBytesDeserializer {
value: value,
marker: PhantomData,
}
}
}
impl<'de, E> de::Deserializer<'de> for BorrowedBytesDeserializer<'de, E>
where
E: de::Error,
{
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_borrowed_bytes(self.value)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct identifier ignored_any enum
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -258,6 +258,7 @@ mod macros;
#[macro_use] #[macro_use]
mod integer128; mod integer128;
#[macro_use]
pub mod de; pub mod de;
pub mod ser; pub mod ser;

View File

@ -1,6 +1,7 @@
use lib::*; use lib::*;
use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor}; use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
use de::value::{BytesDeserializer, BorrowedBytesDeserializer};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use de::{MapAccess, Unexpected}; use de::{MapAccess, Unexpected};
@ -2538,8 +2539,10 @@ mod content {
// } // }
pub trait IdentifierDeserializer<'de, E: Error> { pub trait IdentifierDeserializer<'de, E: Error> {
type Deserializer: Deserializer<'de, Error = E>; type Deserializer: Deserializer<'de, Error = E>;
type BorrowedDeserializer: Deserializer<'de, Error = E>;
fn from(self) -> Self::Deserializer; fn from(self) -> Self::Deserializer;
fn borrowed(self) -> Self::BorrowedDeserializer;
} }
impl<'de, E> IdentifierDeserializer<'de, E> for u32 impl<'de, E> IdentifierDeserializer<'de, E> for u32
@ -2547,87 +2550,49 @@ where
E: Error, E: Error,
{ {
type Deserializer = <u32 as IntoDeserializer<'de, E>>::Deserializer; type Deserializer = <u32 as IntoDeserializer<'de, E>>::Deserializer;
type BorrowedDeserializer = <u32 as IntoDeserializer<'de, E>>::Deserializer;
fn from(self) -> Self::Deserializer { fn from(self) -> Self::Deserializer {
self.into_deserializer() self.into_deserializer()
} }
fn borrowed(self) -> Self::BorrowedDeserializer {
self.into_deserializer()
}
} }
pub struct StrDeserializer<'a, E> { forward_deserializer!(ref StrDeserializer<'a>(&'a str) => visit_str);
value: &'a str, forward_deserializer!(borrowed BorrowedStrDeserializer(&'de str) => visit_borrowed_str);
marker: PhantomData<E>,
}
impl<'a, E> IdentifierDeserializer<'a, E> for &'a str impl<'a, E> IdentifierDeserializer<'a, E> for &'a str
where where
E: Error, E: Error,
{ {
type Deserializer = StrDeserializer<'a, E>; type Deserializer = StrDeserializer<'a, E>;
type BorrowedDeserializer = BorrowedStrDeserializer<'a, E>;
fn from(self) -> Self::Deserializer { fn from(self) -> Self::Deserializer {
StrDeserializer { StrDeserializer::new(self)
value: self,
marker: PhantomData,
}
}
}
impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E>
where
E: Error,
{
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_str(self.value)
} }
forward_to_deserialize_any! { fn borrowed(self) -> Self::BorrowedDeserializer {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string BorrowedStrDeserializer::new(self)
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
} }
} }
pub struct BytesDeserializer<'a, E> {
value: &'a [u8],
marker: PhantomData<E>,
}
impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8] impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8]
where where
E: Error, E: Error,
{ {
type Deserializer = BytesDeserializer<'a, E>; type Deserializer = BytesDeserializer<'a, E>;
type BorrowedDeserializer = BorrowedBytesDeserializer<'a, E>;
fn from(self) -> Self::Deserializer { fn from(self) -> Self::Deserializer {
BytesDeserializer { BytesDeserializer::new(self)
value: self,
marker: PhantomData,
}
}
}
impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
where
E: Error,
{
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_bytes(self.value)
} }
forward_to_deserialize_any! { fn borrowed(self) -> Self::BorrowedDeserializer {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string BorrowedBytesDeserializer::new(self)
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
} }
} }

View File

@ -1891,17 +1891,26 @@ fn deserialize_generated_identifier(
let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() { let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() {
let ignore_variant = quote!(__other(_serde::__private::de::Content<'de>),); let ignore_variant = quote!(__other(_serde::__private::de::Content<'de>),);
let fallthrough = quote!(_serde::__private::Ok(__Field::__other(__value))); let fallthrough = quote!(_serde::__private::Ok(__Field::__other(__value)));
(Some(ignore_variant), Some(fallthrough)) (
Some(ignore_variant),
Some((fallthrough.clone(), fallthrough))
)
} else if let Some(other_idx) = other_idx { } else if let Some(other_idx) = other_idx {
let ignore_variant = fields[other_idx].1.clone(); let ignore_variant = fields[other_idx].1.clone();
let fallthrough = quote!(_serde::__private::Ok(__Field::#ignore_variant)); let fallthrough = quote!(_serde::__private::Ok(__Field::#ignore_variant));
(None, Some(fallthrough)) (
None,
Some((fallthrough.clone(), fallthrough))
)
} else if is_variant || cattrs.deny_unknown_fields() { } else if is_variant || cattrs.deny_unknown_fields() {
(None, None) (None, None)
} else { } else {
let ignore_variant = quote!(__ignore,); let ignore_variant = quote!(__ignore,);
let fallthrough = quote!(_serde::__private::Ok(__Field::__ignore)); let fallthrough = quote!(_serde::__private::Ok(__Field::__ignore));
(Some(ignore_variant), Some(fallthrough)) (
Some(ignore_variant),
Some((fallthrough.clone(), fallthrough))
)
}; };
let visitor_impl = Stmts(deserialize_identifier( let visitor_impl = Stmts(deserialize_identifier(
@ -1964,16 +1973,26 @@ fn deserialize_custom_identifier(
if last.attrs.other() { if last.attrs.other() {
let ordinary = &variants[..variants.len() - 1]; let ordinary = &variants[..variants.len() - 1];
let fallthrough = quote!(_serde::__private::Ok(#this::#last_ident)); let fallthrough = quote!(_serde::__private::Ok(#this::#last_ident));
(ordinary, Some(fallthrough)) (
ordinary,
Some((fallthrough.clone(), fallthrough))
)
} else if let Style::Newtype = last.style { } else if let Style::Newtype = last.style {
let ordinary = &variants[..variants.len() - 1]; let ordinary = &variants[..variants.len() - 1];
let deserializer = quote!(_serde::__private::de::IdentifierDeserializer::from(__value)); let fallthrough = |method| quote! {
let fallthrough = quote! {
_serde::__private::Result::map( _serde::__private::Result::map(
_serde::Deserialize::deserialize(#deserializer), _serde::Deserialize::deserialize(
_serde::__private::de::IdentifierDeserializer::#method(__value)
),
#this::#last_ident) #this::#last_ident)
}; };
(ordinary, Some(fallthrough)) (
ordinary,
Some((
fallthrough(quote!(from)),
fallthrough(quote!(borrowed)),
))
)
} else { } else {
(variants, None) (variants, None)
} }
@ -2045,7 +2064,8 @@ fn deserialize_identifier(
this: &TokenStream, this: &TokenStream,
fields: &[(String, Ident, Vec<String>)], fields: &[(String, Ident, Vec<String>)],
is_variant: bool, is_variant: bool,
fallthrough: Option<TokenStream>, // .0 for referenced data, .1 -- for borrowed
fallthrough: Option<(TokenStream, TokenStream)>,
collect_other_fields: bool, collect_other_fields: bool,
) -> Fragment { ) -> Fragment {
let mut flat_fields = Vec::new(); let mut flat_fields = Vec::new();
@ -2053,14 +2073,11 @@ fn deserialize_identifier(
flat_fields.extend(aliases.iter().map(|alias| (alias, ident))) flat_fields.extend(aliases.iter().map(|alias| (alias, ident)))
} }
let field_strs = flat_fields.iter().map(|(name, _)| name); let field_strs: &Vec<_> = &flat_fields.iter().map(|(name, _)| name).collect();
let field_borrowed_strs = flat_fields.iter().map(|(name, _)| name); let field_bytes: &Vec<_> = &flat_fields
let field_bytes = flat_fields
.iter() .iter()
.map(|(name, _)| Literal::byte_string(name.as_bytes())); .map(|(name, _)| Literal::byte_string(name.as_bytes()))
let field_borrowed_bytes = flat_fields .collect();
.iter()
.map(|(name, _)| Literal::byte_string(name.as_bytes()));
let constructors: &Vec<_> = &flat_fields let constructors: &Vec<_> = &flat_fields
.iter() .iter()
@ -2111,16 +2128,21 @@ fn deserialize_identifier(
(None, None, None, None) (None, None, None, None)
}; };
let fallthrough_arm = if let Some(fallthrough) = fallthrough { let (
fallthrough_arm,
fallthrough_borrowed_arm,
) = if let Some(fallthrough) = fallthrough.clone() {
fallthrough fallthrough
} else if is_variant { } else if is_variant {
quote! { let fallthrough = quote! {
_serde::__private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) _serde::__private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS))
} };
(fallthrough.clone(), fallthrough)
} else { } else {
quote! { let fallthrough = quote! {
_serde::__private::Err(_serde::de::Error::unknown_field(__value, FIELDS)) _serde::__private::Err(_serde::de::Error::unknown_field(__value, FIELDS))
} };
(fallthrough.clone(), fallthrough)
}; };
let variant_indices = 0_u64..; let variant_indices = 0_u64..;
@ -2217,37 +2239,6 @@ fn deserialize_identifier(
{ {
_serde::__private::Ok(__Field::__other(_serde::__private::de::Content::Unit)) _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::Unit))
} }
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(
#field_borrowed_strs => _serde::__private::Ok(#constructors),
)*
_ => {
#value_as_borrowed_str_content
#fallthrough_arm
}
}
}
fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::__private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(
#field_borrowed_bytes => _serde::__private::Ok(#constructors),
)*
_ => {
#bytes_to_str
#value_as_borrowed_bytes_content
#fallthrough_arm
}
}
}
} }
} else { } else {
quote! { quote! {
@ -2290,6 +2281,21 @@ fn deserialize_identifier(
} }
} }
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(
#field_strs => _serde::__private::Ok(#constructors),
)*
_ => {
#value_as_borrowed_str_content
#fallthrough_borrowed_arm
}
}
}
fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::__private::Result<Self::Value, __E> fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::__private::Result<Self::Value, __E>
where where
__E: _serde::de::Error, __E: _serde::de::Error,
@ -2305,6 +2311,22 @@ fn deserialize_identifier(
} }
} }
} }
fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::__private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(
#field_bytes => _serde::__private::Ok(#constructors),
)*
_ => {
#bytes_to_str
#value_as_borrowed_bytes_content
#fallthrough_borrowed_arm
}
}
}
} }
} }

View File

@ -90,6 +90,37 @@ fn test_struct() {
); );
} }
#[test]
fn test_field_identifier() {
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier)]
enum FieldStr<'a> {
#[serde(borrow)]
Str(&'a str),
}
assert_de_tokens(
&FieldStr::Str("value"),
&[
Token::BorrowedStr("value"),
],
);
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier)]
enum FieldBytes<'a> {
#[serde(borrow)]
Bytes(&'a [u8]),
}
assert_de_tokens(
&FieldBytes::Bytes(b"value"),
&[
Token::BorrowedBytes(b"value"),
],
);
}
#[test] #[test]
fn test_cow() { fn test_cow() {
#[derive(Deserialize)] #[derive(Deserialize)]