From 094f63b86ae5b7a9a7ee01da9f3dac38d566cfe9 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 23 Oct 2020 13:03:19 +0500 Subject: [PATCH] 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 7c247460..19cc7100 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 +); ////////////////////////////////////////////////////////////////////////////////