From 42fa79455e737e9b9ac212770705ce4144cda171 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 3 Oct 2020 16:30:19 +0500 Subject: [PATCH 1/4] Make `BytesDeserializer` public --- serde/src/de/value.rs | 47 ++++++++++++++++++++++++++++++++++++++--- serde/src/private/de.rs | 31 ++------------------------- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/serde/src/de/value.rs b/serde/src/de/value.rs index 4044f322b..7c247460e 100644 --- a/serde/src/de/value.rs +++ b/serde/src/de/value.rs @@ -665,6 +665,47 @@ where //////////////////////////////////////////////////////////////////////////////// +/// A deserializer holding a `&[u8]`. +#[derive(Debug)] +pub struct BytesDeserializer<'a, E> { + value: &'a [u8], + marker: PhantomData, +} + +impl_copy_clone!(BytesDeserializer<'de>); + +impl<'a, E> BytesDeserializer<'a, E> { + /// Create a new deserializer from the given slice. + pub fn new(value: &'a [u8]) -> Self { + BytesDeserializer { + value: value, + marker: PhantomData, + } + } +} + +impl<'de, 'a, E> de::Deserializer<'de> for BytesDeserializer<'a, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_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 enum identifier ignored_any + } +} + +//////////////////////////////////////////////////////////////////////////////// + /// A deserializer holding a `&[u8]` with a lifetime tied to another /// deserializer. #[derive(Debug)] @@ -699,9 +740,9 @@ where } 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 + 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 } } diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index bcb964a9c..57dad9aaf 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; #[cfg(any(feature = "std", feature = "alloc"))] use de::{MapAccess, Unexpected}; @@ -2592,11 +2593,6 @@ where } } -pub struct BytesDeserializer<'a, E> { - value: &'a [u8], - marker: PhantomData, -} - impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8] where E: Error, @@ -2604,30 +2600,7 @@ where type Deserializer = BytesDeserializer<'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) - } - - 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 + BytesDeserializer::new(self) } } From 094f63b86ae5b7a9a7ee01da9f3dac38d566cfe9 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 23 Oct 2020 13:03:19 +0500 Subject: [PATCH 2/4] Introduce a forward_deserializer macro. It helps to create deserializers that can stop time: save the value and then use visitor to get it later! --- serde/src/de/value.rs | 191 ++++++++++++++++++++++++------------------ 1 file changed, 109 insertions(+), 82 deletions(-) diff --git a/serde/src/de/value.rs b/serde/src/de/value.rs index 7c247460e..19cc71004 100644 --- a/serde/src/de/value.rs +++ b/serde/src/de/value.rs @@ -30,8 +30,8 @@ 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). macro_rules! impl_copy_clone { ($ty:ident $(<$lifetime:tt>)*) => { impl<$($lifetime,)* E> Copy for $ty<$($lifetime,)* E> {} @@ -44,6 +44,100 @@ macro_rules! impl_copy_clone { }; } +/// Creates a deserializer any method of which forwards to the specified visitor method +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> de::Deserializer<'de> for $deserializer<$($lifetime,)* E> + where + E: de::Error, + { + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: 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> de::Deserializer<'de> for $deserializer<'de, E> + where + E: de::Error, + { + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: 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,86 +759,19 @@ where //////////////////////////////////////////////////////////////////////////////// -/// A deserializer holding a `&[u8]`. -#[derive(Debug)] -pub struct BytesDeserializer<'a, E> { - value: &'a [u8], - marker: PhantomData, -} - -impl_copy_clone!(BytesDeserializer<'de>); - -impl<'a, E> BytesDeserializer<'a, E> { - /// Create a new deserializer from the given slice. - pub fn new(value: &'a [u8]) -> Self { - BytesDeserializer { - value: value, - marker: PhantomData, - } - } -} - -impl<'de, 'a, E> de::Deserializer<'de> for BytesDeserializer<'a, E> -where - E: de::Error, -{ - type Error = E; - - fn deserialize_any(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_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 enum identifier ignored_any - } -} - -//////////////////////////////////////////////////////////////////////////////// - -/// 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 enum identifier ignored_any - } -} +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 +); //////////////////////////////////////////////////////////////////////////////// From 9e1f573f8879916998e4310ae2516e662fa753db Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 23 Oct 2020 14:06:04 +0500 Subject: [PATCH 3/4] Use forward_deserializer macro for define StrDeserializer for IdentifierDeserializer --- serde/src/de/mod.rs | 1 + serde/src/de/value.rs | 20 ++++++++++++-------- serde/src/lib.rs | 1 + serde/src/private/de.rs | 30 ++---------------------------- 4 files changed, 16 insertions(+), 36 deletions(-) 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 19cc71004..15fb76e3e 100644 --- a/serde/src/de/value.rs +++ b/serde/src/de/value.rs @@ -32,6 +32,8 @@ use ser; /// 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> {} @@ -45,6 +47,8 @@ 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 ( @@ -72,15 +76,15 @@ macro_rules! forward_deserializer { impl_copy_clone!($deserializer $(<$lifetime>)*); - impl<'de, $($lifetime,)* E> de::Deserializer<'de> for $deserializer<$($lifetime,)* E> + impl<'de, $($lifetime,)* E> $crate::de::Deserializer<'de> for $deserializer<$($lifetime,)* E> where - E: de::Error, + E: $crate::de::Error, { type Error = E; - fn deserialize_any(self, visitor: V) -> Result + fn deserialize_any(self, visitor: V) -> $crate::export::Result where - V: de::Visitor<'de>, + V: $crate::de::Visitor<'de>, { visitor.$visit(self.value) } @@ -116,15 +120,15 @@ macro_rules! forward_deserializer { impl_copy_clone!($deserializer<'de>); - impl<'de, E> de::Deserializer<'de> for $deserializer<'de, E> + impl<'de, E> $crate::de::Deserializer<'de> for $deserializer<'de, E> where - E: de::Error, + E: $crate::de::Error, { type Error = E; - fn deserialize_any(self, visitor: V) -> Result + fn deserialize_any(self, visitor: V) -> $crate::export::Result where - V: de::Visitor<'de>, + V: $crate::de::Visitor<'de>, { visitor.$visit(self.value) } diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 0acf0583a..1f37a3f1b 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -256,6 +256,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 57dad9aaf..270525402 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -2554,10 +2554,7 @@ where } } -pub struct StrDeserializer<'a, E> { - value: &'a str, - marker: PhantomData, -} +forward_deserializer!(ref StrDeserializer<'a>(&'a str) => visit_str); impl<'a, E> IdentifierDeserializer<'a, E> for &'a str where @@ -2566,30 +2563,7 @@ where type Deserializer = StrDeserializer<'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) - } - - 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 + StrDeserializer::new(self) } } From 7a7a182ab6cb4b9ad4d7b0e332fb8ee010a6fc40 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 23 Oct 2020 16:12:06 +0500 Subject: [PATCH 4/4] Allow borrow for field identifiers --- serde/src/private/de.rs | 44 ++++++++--- serde_derive/src/de.rs | 127 +++++++++++++++++++------------- test_suite/tests/test_borrow.rs | 31 ++++++++ 3 files changed, 139 insertions(+), 63 deletions(-) diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index 270525402..76d260bc2 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -1,7 +1,7 @@ use lib::*; use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor}; -use de::value::BytesDeserializer; +use de::value::{BytesDeserializer, BorrowedBytesDeserializer}; #[cfg(any(feature = "std", feature = "alloc"))] use de::{MapAccess, Unexpected}; @@ -2527,20 +2527,26 @@ mod content { //////////////////////////////////////////////////////////////////////////////// -// Like `IntoDeserializer` but also implemented for `&[u8]`. This is used for -// the newtype fallthrough case of `field_identifier`. -// -// #[derive(Deserialize)] -// #[serde(field_identifier)] -// enum F { -// A, -// B, -// Other(String), // deserialized using IdentifierDeserializer -// } +/// Like `IntoDeserializer` but also implemented for `&[u8]`. This is used for +/// the newtype fallthrough case of `field_identifier`. +/// +/// ```ignore +/// #[derive(Deserialize)] +/// #[serde(field_identifier)] +/// enum F { +/// A, +/// B, +/// Other(String), // deserialized using IdentifierDeserializer +/// } +/// ``` pub trait IdentifierDeserializer<'de, E: Error> { + /// Deserializer, that refers to data owned by deserializer type Deserializer: Deserializer<'de, Error = E>; + /// Deserializer, that borrows data from the input + type BorrowedDeserializer: Deserializer<'de, Error = E>; fn from(self) -> Self::Deserializer; + fn borrowed(self) -> Self::BorrowedDeserializer; } impl<'de, E> IdentifierDeserializer<'de, E> for u32 @@ -2548,23 +2554,34 @@ where E: Error, { type Deserializer = >::Deserializer; + type BorrowedDeserializer = >::Deserializer; fn from(self) -> Self::Deserializer { self.into_deserializer() } + + 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::new(self) } + + fn borrowed(self) -> Self::BorrowedDeserializer { + BorrowedStrDeserializer::new(self) + } } impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8] @@ -2572,10 +2589,15 @@ where E: Error, { type Deserializer = BytesDeserializer<'a, E>; + type BorrowedDeserializer = BorrowedBytesDeserializer<'a, E>; fn from(self) -> Self::Deserializer { BytesDeserializer::new(self) } + + fn borrowed(self) -> Self::BorrowedDeserializer { + BorrowedBytesDeserializer::new(self) + } } /// A DeserializeSeed helper for implementing deserialize_in_place Visitors. diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 1f5733a6d..704985dee 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1886,17 +1886,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::export::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::export::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::export::Ok(__Field::__ignore)); - (Some(ignore_variant), Some(fallthrough)) + ( + Some(ignore_variant), + Some((fallthrough.clone(), fallthrough)) + ) }; let visitor_impl = Stmts(deserialize_identifier( @@ -1959,16 +1968,27 @@ fn deserialize_custom_identifier( if last.attrs.other() { let ordinary = &variants[..variants.len() - 1]; let fallthrough = quote!(_serde::export::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::export::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) } @@ -2040,7 +2060,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(); @@ -2048,14 +2069,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 - .iter() - .map(|(name, _)| Literal::byte_string(name.as_bytes())); - let field_borrowed_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())); + .map(|(name, _)| Literal::byte_string(name.as_bytes())) + .collect(); let constructors: &Vec<_> = &flat_fields .iter() @@ -2106,16 +2124,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::export::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) - } + }; + (fallthrough.clone(), fallthrough) } else { - quote! { + let fallthrough = quote! { _serde::export::Err(_serde::de::Error::unknown_field(__value, FIELDS)) - } + }; + (fallthrough.clone(), fallthrough) }; let variant_indices = 0_u64..; @@ -2212,37 +2235,6 @@ fn deserialize_identifier( { _serde::export::Ok(__Field::__other(_serde::private::de::Content::Unit)) } - - fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - #( - #field_borrowed_strs => _serde::export::Ok(#constructors), - )* - _ => { - #value_as_borrowed_str_content - #fallthrough_arm - } - } - } - - fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::export::Result - where - __E: _serde::de::Error, - { - match __value { - #( - #field_borrowed_bytes => _serde::export::Ok(#constructors), - )* - _ => { - #bytes_to_str - #value_as_borrowed_bytes_content - #fallthrough_arm - } - } - } } } else { quote! { @@ -2285,6 +2277,21 @@ fn deserialize_identifier( } } + fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::export::Result + where + __E: _serde::de::Error, + { + match __value { + #( + #field_strs => _serde::export::Ok(#constructors), + )* + _ => { + #value_as_borrowed_str_content + #fallthrough_borrowed_arm + } + } + } + fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::export::Result where __E: _serde::de::Error, @@ -2300,6 +2307,22 @@ fn deserialize_identifier( } } } + + fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::export::Result + where + __E: _serde::de::Error, + { + match __value { + #( + #field_bytes => _serde::export::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)]