Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to borrow data when deserializing field identifiers #1917

Merged
merged 4 commits into from Jan 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions serde/src/de/mod.rs
Expand Up @@ -116,6 +116,7 @@ use lib::*;

////////////////////////////////////////////////////////////////////////////////

#[macro_use]
pub mod value;

mod from_primitive;
Expand Down
154 changes: 113 additions & 41 deletions serde/src/de/value.rs
Expand Up @@ -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> {}
Expand All @@ -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
Expand Down Expand Up @@ -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<E>,
}

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<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
}
}
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
);

////////////////////////////////////////////////////////////////////////////////

Expand Down
1 change: 1 addition & 0 deletions serde/src/lib.rs
Expand Up @@ -256,6 +256,7 @@ mod macros;
#[macro_use]
mod integer128;

#[macro_use]
pub mod de;
pub mod ser;

Expand Down
95 changes: 32 additions & 63 deletions 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};
Expand Down Expand Up @@ -2526,108 +2527,76 @@ 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
where
E: Error,
{
type Deserializer = <u32 as IntoDeserializer<'de, E>>::Deserializer;
type BorrowedDeserializer = <u32 as IntoDeserializer<'de, E>>::Deserializer;

fn from(self) -> Self::Deserializer {
self.into_deserializer()
}
}

pub struct StrDeserializer<'a, E> {
value: &'a str,
marker: PhantomData<E>,
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,
}
StrDeserializer::new(self)
}
}

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)
fn borrowed(self) -> Self::BorrowedDeserializer {
BorrowedStrDeserializer::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
}
}

pub struct BytesDeserializer<'a, E> {
value: &'a [u8],
marker: PhantomData<E>,
}

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<V>(self, visitor: V) -> Result<V::Value, Self::Error>
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)
}
}

Expand Down