diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index 6d3947363..1f0c8adc1 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -116,6 +116,7 @@ use lib::*; //////////////////////////////////////////////////////////////////////////////// +#[macro_use] pub mod value; mod from_primitive; diff --git a/serde/src/de/value.rs b/serde/src/de/value.rs index 96f2a90f7..fcacb0c3f 100644 --- a/serde/src/de/value.rs +++ b/serde/src/de/value.rs @@ -30,8 +30,10 @@ use ser; //////////////////////////////////////////////////////////////////////////////// -// For structs that contain a PhantomData. We do not want the trait -// bound `E: Clone` inferred by derive(Clone). +/// For structs that contain a PhantomData. We do not want the trait +/// bound `E: Clone` inferred by derive(Clone). +#[doc(hidden)] +#[macro_export] macro_rules! impl_copy_clone { ($ty:ident $(<$lifetime:tt>)*) => { 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, + } + + 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(self, visitor: V) -> $crate::export::Result + 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, + } + + 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(self, visitor: V) -> $crate::export::Result + 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 @@ -665,45 +763,19 @@ where //////////////////////////////////////////////////////////////////////////////// -/// A deserializer holding a `&[u8]` with a lifetime tied to another -/// deserializer. -#[derive(Debug)] -pub struct BorrowedBytesDeserializer<'de, E> { - value: &'de [u8], - marker: PhantomData, -} - -impl_copy_clone!(BorrowedBytesDeserializer<'de>); - -impl<'de, E> BorrowedBytesDeserializer<'de, E> { - /// Create a new borrowed deserializer from the given byte slice. - 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(self, visitor: V) -> Result - 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 - } -} +forward_deserializer!( + /// A deserializer holding a `&[u8]`. Always call [`Visitor::visit_bytes`] + /// + /// [`Visitor::visit_bytes`]: ../struct.Visitor.html#method.visit_bytes + ref BytesDeserializer<'a>(&'a [u8]) => visit_bytes +); +forward_deserializer!( + /// A deserializer holding a `&[u8]` with a lifetime tied to another + /// deserializer. Always call [`Visitor::visit_borrowed_bytes`] + /// + /// [`Visitor::visit_borrowed_bytes`]: ../struct.Visitor.html#method.visit_borrowed_bytes + borrowed BorrowedBytesDeserializer(&'de [u8]) => visit_borrowed_bytes +); //////////////////////////////////////////////////////////////////////////////// diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 8cc8faea3..bc7b9401c 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -258,6 +258,7 @@ mod macros; #[macro_use] mod integer128; +#[macro_use] pub mod de; pub mod ser; diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index bcb964a9c..24d2d691b 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -1,6 +1,7 @@ use lib::*; use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor}; +use de::value::{BytesDeserializer, BorrowedBytesDeserializer}; #[cfg(any(feature = "std", feature = "alloc"))] use de::{MapAccess, Unexpected}; @@ -2538,8 +2539,10 @@ mod content { // } pub trait IdentifierDeserializer<'de, E: Error> { type Deserializer: Deserializer<'de, Error = E>; + type BorrowedDeserializer: Deserializer<'de, Error = E>; fn from(self) -> Self::Deserializer; + fn borrowed(self) -> Self::BorrowedDeserializer; } impl<'de, E> IdentifierDeserializer<'de, E> for u32 @@ -2547,87 +2550,49 @@ where E: Error, { type Deserializer = >::Deserializer; + type BorrowedDeserializer = >::Deserializer; fn from(self) -> Self::Deserializer { self.into_deserializer() } -} -pub struct StrDeserializer<'a, E> { - value: &'a str, - marker: PhantomData, + fn borrowed(self) -> Self::BorrowedDeserializer { + self.into_deserializer() + } } +forward_deserializer!(ref StrDeserializer<'a>(&'a str) => visit_str); +forward_deserializer!(borrowed BorrowedStrDeserializer(&'de str) => visit_borrowed_str); + impl<'a, E> IdentifierDeserializer<'a, E> for &'a str where E: Error, { type Deserializer = StrDeserializer<'a, E>; + type BorrowedDeserializer = BorrowedStrDeserializer<'a, E>; fn from(self) -> Self::Deserializer { - StrDeserializer { - value: self, - marker: PhantomData, - } - } -} - -impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E> -where - E: Error, -{ - type Error = E; - - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - visitor.visit_str(self.value) + StrDeserializer::new(self) } - 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 + fn borrowed(self) -> Self::BorrowedDeserializer { + BorrowedStrDeserializer::new(self) } } -pub struct BytesDeserializer<'a, E> { - value: &'a [u8], - marker: PhantomData, -} - impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8] where E: Error, { type Deserializer = BytesDeserializer<'a, E>; + type BorrowedDeserializer = BorrowedBytesDeserializer<'a, E>; fn from(self) -> Self::Deserializer { - BytesDeserializer { - value: self, - marker: PhantomData, - } - } -} - -impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E> -where - E: Error, -{ - type Error = E; - - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - visitor.visit_bytes(self.value) + BytesDeserializer::new(self) } - 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 + fn borrowed(self) -> Self::BorrowedDeserializer { + BorrowedBytesDeserializer::new(self) } } diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 10033e4b5..c9a4bd344 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1891,17 +1891,26 @@ fn deserialize_generated_identifier( let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() { let ignore_variant = quote!(__other(_serde::__private::de::Content<'de>),); 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 { let ignore_variant = fields[other_idx].1.clone(); 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() { (None, None) } else { let ignore_variant = quote!(__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( @@ -1964,16 +1973,26 @@ fn deserialize_custom_identifier( if last.attrs.other() { let ordinary = &variants[..variants.len() - 1]; let fallthrough = quote!(_serde::__private::Ok(#this::#last_ident)); - (ordinary, Some(fallthrough)) + ( + ordinary, + Some((fallthrough.clone(), fallthrough)) + ) } else if let Style::Newtype = last.style { let ordinary = &variants[..variants.len() - 1]; - let deserializer = quote!(_serde::__private::de::IdentifierDeserializer::from(__value)); - let fallthrough = quote! { + let fallthrough = |method| quote! { _serde::__private::Result::map( - _serde::Deserialize::deserialize(#deserializer), + _serde::Deserialize::deserialize( + _serde::__private::de::IdentifierDeserializer::#method(__value) + ), #this::#last_ident) }; - (ordinary, Some(fallthrough)) + ( + ordinary, + Some(( + fallthrough(quote!(from)), + fallthrough(quote!(borrowed)), + )) + ) } else { (variants, None) } @@ -2045,7 +2064,8 @@ fn deserialize_identifier( this: &TokenStream, fields: &[(String, Ident, Vec)], is_variant: bool, - fallthrough: Option, + // .0 for referenced data, .1 -- for borrowed + fallthrough: Option<(TokenStream, TokenStream)>, collect_other_fields: bool, ) -> Fragment { let mut flat_fields = Vec::new(); @@ -2053,14 +2073,11 @@ fn deserialize_identifier( flat_fields.extend(aliases.iter().map(|alias| (alias, ident))) } - let field_strs = flat_fields.iter().map(|(name, _)| name); - let field_borrowed_strs = flat_fields.iter().map(|(name, _)| name); - let field_bytes = flat_fields + let field_strs: &Vec<_> = &flat_fields.iter().map(|(name, _)| name).collect(); + let field_bytes: &Vec<_> = &flat_fields .iter() - .map(|(name, _)| Literal::byte_string(name.as_bytes())); - let field_borrowed_bytes = flat_fields - .iter() - .map(|(name, _)| Literal::byte_string(name.as_bytes())); + .map(|(name, _)| Literal::byte_string(name.as_bytes())) + .collect(); let constructors: &Vec<_> = &flat_fields .iter() @@ -2111,16 +2128,21 @@ fn deserialize_identifier( (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 } else if is_variant { - quote! { + let fallthrough = quote! { _serde::__private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) - } + }; + (fallthrough.clone(), fallthrough) } else { - quote! { + let fallthrough = quote! { _serde::__private::Err(_serde::de::Error::unknown_field(__value, FIELDS)) - } + }; + (fallthrough.clone(), fallthrough) }; let variant_indices = 0_u64..; @@ -2217,37 +2239,6 @@ fn deserialize_identifier( { _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::Unit)) } - - fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result - 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 - 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 { quote! { @@ -2290,6 +2281,21 @@ fn deserialize_identifier( } } + fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result + 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 where __E: _serde::de::Error, @@ -2305,6 +2311,22 @@ fn deserialize_identifier( } } } + + fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::__private::Result + where + __E: _serde::de::Error, + { + match __value { + #( + #field_bytes => _serde::__private::Ok(#constructors), + )* + _ => { + #bytes_to_str + #value_as_borrowed_bytes_content + #fallthrough_borrowed_arm + } + } + } } } diff --git a/test_suite/tests/test_borrow.rs b/test_suite/tests/test_borrow.rs index e76ede69f..15139cb9f 100644 --- a/test_suite/tests/test_borrow.rs +++ b/test_suite/tests/test_borrow.rs @@ -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] fn test_cow() { #[derive(Deserialize)]