mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-25 23:17:56 +00:00
Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c04c98e0e | |||
| a2fa4c2570 | |||
| 42430902e2 | |||
| 23e2e92237 | |||
| 273b2c11c6 | |||
| c1602a4d76 | |||
| c23be3f855 | |||
| 5c9c97c0ce | |||
| e5ed440136 | |||
| d45ca2f5e4 | |||
| d7f9f8209d | |||
| 4a2612ecff | |||
| 05b22a06d7 | |||
| 3145bcc46e | |||
| 2b18b57d84 | |||
| 5520202262 | |||
| 3d647f4063 | |||
| 0fde3c2ee8 | |||
| 27f935f036 | |||
| 99614c7266 | |||
| bb2ecb3bc4 | |||
| 96393bfcc7 | |||
| 1d92569abc | |||
| e4ef087735 | |||
| 695c3eedcb | |||
| 50c636a923 | |||
| 5b884b5bf9 | |||
| 8637dda60f | |||
| abeea89147 | |||
| 6e324e887d | |||
| 7c596c7136 | |||
| f02dbf381b | |||
| 7cf184624a | |||
| c5a3128492 | |||
| 205f606962 | |||
| ad40f976db | |||
| 58d52e784b | |||
| d44f12907b | |||
| 61b167be9a | |||
| f1af2dc5ab | |||
| ebc61baab2 | |||
| ffcde25b6e | |||
| 2f57cecf13 | |||
| bfdcbae9db | |||
| ca41e16e92 | |||
| 352fe7b451 | |||
| 49e302d17d | |||
| b8602a7e43 | |||
| a8c8c2028e | |||
| d1833c5602 | |||
| b4ef7ac323 | |||
| ebf80ac965 | |||
| 112dfd7428 | |||
| b692923321 | |||
| 9e8cda4c37 | |||
| 5457394f5b | |||
| 6627540dd6 | |||
| 5ae06bba49 | |||
| 571bb8caed | |||
| 299cd2dbd0 | |||
| 583c0d8d14 | |||
| 07d07347b3 | |||
| 77b07f3fbf | |||
| 1bd2c6129c | |||
| 39413c8ce7 | |||
| b4dbae250b | |||
| 5a91ac5ba5 | |||
| 7ad836e6a9 | |||
| 72ecb9064c | |||
| f9946ee0ca | |||
| a164f52315 |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.32" # remember to update html_root_url
|
version = "1.0.36" # remember to update html_root_url
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
description = "A generic serialization/deserialization framework"
|
description = "A generic serialization/deserialization framework"
|
||||||
|
|||||||
@@ -1918,6 +1918,7 @@ where
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
|
#[allow(deprecated)]
|
||||||
impl<'de, T> Deserialize<'de> for NonZero<T>
|
impl<'de, T> Deserialize<'de> for NonZero<T>
|
||||||
where
|
where
|
||||||
T: Deserialize<'de> + Zeroable,
|
T: Deserialize<'de> + Zeroable,
|
||||||
@@ -1934,6 +1935,36 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! nonzero_integers {
|
||||||
|
( $( $T: ty, )+ ) => {
|
||||||
|
$(
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
|
impl<'de> Deserialize<'de> for $T {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<$T, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let value = try!(Deserialize::deserialize(deserializer));
|
||||||
|
match <$T>::new(value) {
|
||||||
|
Some(nonzero) => Ok(nonzero),
|
||||||
|
None => Err(Error::custom("expected a non-zero value")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
nonzero_integers! {
|
||||||
|
// Not including signed NonZeroI* since they might be removed
|
||||||
|
NonZeroU8,
|
||||||
|
NonZeroU16,
|
||||||
|
NonZeroU32,
|
||||||
|
NonZeroU64,
|
||||||
|
// FIXME: https://github.com/serde-rs/serde/issues/1136 NonZeroU128,
|
||||||
|
NonZeroUsize,
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl<'de, T, E> Deserialize<'de> for Result<T, E>
|
impl<'de, T, E> Deserialize<'de> for Result<T, E>
|
||||||
|
|||||||
+2
-1
@@ -98,7 +98,8 @@
|
|||||||
//! - Path
|
//! - Path
|
||||||
//! - PathBuf
|
//! - PathBuf
|
||||||
//! - Range\<T\>
|
//! - Range\<T\>
|
||||||
//! - NonZero\<T\> (unstable)
|
//! - NonZero\<T\> (unstable, deprecated)
|
||||||
|
//! - num::NonZero* (unstable)
|
||||||
//! - **Net types**:
|
//! - **Net types**:
|
||||||
//! - IpAddr
|
//! - IpAddr
|
||||||
//! - Ipv4Addr
|
//! - Ipv4Addr
|
||||||
|
|||||||
+5
-1
@@ -79,7 +79,7 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Serde types in rustdoc of other crates get linked to here.
|
// Serde types in rustdoc of other crates get linked to here.
|
||||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.32")]
|
#![doc(html_root_url = "https://docs.rs/serde/1.0.36")]
|
||||||
// Support using Serde without the standard library!
|
// Support using Serde without the standard library!
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
// Unstable functionality only if the user asks for it. For tracking and
|
// Unstable functionality only if the user asks for it. For tracking and
|
||||||
@@ -211,7 +211,11 @@ mod lib {
|
|||||||
pub use std::sync::{Mutex, RwLock};
|
pub use std::sync::{Mutex, RwLock};
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub use core::nonzero::{NonZero, Zeroable};
|
pub use core::nonzero::{NonZero, Zeroable};
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
|
pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize};
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
+184
-9
@@ -11,13 +11,13 @@ use lib::*;
|
|||||||
use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
|
use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use de::Unexpected;
|
use de::{Unexpected, MapAccess};
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub use self::content::{Content, ContentDeserializer, ContentRefDeserializer,
|
pub use self::content::{Content, ContentDeserializer, ContentRefDeserializer,
|
||||||
InternallyTaggedUnitVisitor, TagContentOtherField,
|
InternallyTaggedUnitVisitor, TagContentOtherField,
|
||||||
TagContentOtherFieldVisitor, TagOrContentField, TagOrContentFieldVisitor,
|
TagContentOtherFieldVisitor, TagOrContentField, TagOrContentFieldVisitor,
|
||||||
TaggedContentVisitor, UntaggedUnitVisitor};
|
TaggedContentVisitor, UntaggedUnitVisitor, EnumDeserializer};
|
||||||
|
|
||||||
/// If the missing field is of type `Option<T>` then treat is as `None`,
|
/// If the missing field is of type `Option<T>` then treat is as `None`,
|
||||||
/// otherwise it is an error.
|
/// otherwise it is an error.
|
||||||
@@ -269,6 +269,14 @@ mod content {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Content<'de> {
|
impl<'de> Content<'de> {
|
||||||
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
|
match *self {
|
||||||
|
Content::Str(x) => Some(x),
|
||||||
|
Content::String(ref x) => Some(x),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn unexpected(&self) -> Unexpected {
|
fn unexpected(&self) -> Unexpected {
|
||||||
match *self {
|
match *self {
|
||||||
Content::Bool(b) => Unexpected::Bool(b),
|
Content::Bool(b) => Unexpected::Bool(b),
|
||||||
@@ -1118,11 +1126,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
visitor.visit_enum(EnumDeserializer {
|
visitor.visit_enum(EnumDeserializer::new(variant, value))
|
||||||
variant: variant,
|
|
||||||
value: value,
|
|
||||||
err: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_unit_struct<V>(
|
fn deserialize_unit_struct<V>(
|
||||||
@@ -1170,7 +1174,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EnumDeserializer<'de, E>
|
pub struct EnumDeserializer<'de, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
{
|
{
|
||||||
@@ -1179,6 +1183,18 @@ mod content {
|
|||||||
err: PhantomData<E>,
|
err: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'de, E> EnumDeserializer<'de, E>
|
||||||
|
where E: de::Error
|
||||||
|
{
|
||||||
|
pub fn new(variant: Content<'de>, value: Option<Content<'de>>) -> EnumDeserializer<'de, E> {
|
||||||
|
EnumDeserializer {
|
||||||
|
variant: variant,
|
||||||
|
value: value,
|
||||||
|
err: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'de, E> de::EnumAccess<'de> for EnumDeserializer<'de, E>
|
impl<'de, E> de::EnumAccess<'de> for EnumDeserializer<'de, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
@@ -1199,7 +1215,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VariantDeserializer<'de, E>
|
pub struct VariantDeserializer<'de, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
{
|
{
|
||||||
@@ -2062,3 +2078,162 @@ where
|
|||||||
T::deserialize_in_place(deserializer, self.0)
|
T::deserialize_in_place(deserializer, self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub struct FlatMapDeserializer<'a, 'de: 'a, E>(
|
||||||
|
pub &'a mut Vec<Option<(Content<'de>, Content<'de>)>>,
|
||||||
|
pub PhantomData<E>
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
|
||||||
|
where E: Error
|
||||||
|
{
|
||||||
|
type Error = E;
|
||||||
|
|
||||||
|
fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
Err(Error::custom("can only flatten structs and maps"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_enum<V>(
|
||||||
|
self,
|
||||||
|
name: &'static str,
|
||||||
|
variants: &'static [&'static str],
|
||||||
|
visitor: V
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
for item in self.0.iter_mut() {
|
||||||
|
// items in the vector are nulled out when used. So we can only use
|
||||||
|
// an item if it's still filled in and if the field is one we care
|
||||||
|
// about.
|
||||||
|
let use_item = match *item {
|
||||||
|
None => false,
|
||||||
|
Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x))
|
||||||
|
};
|
||||||
|
|
||||||
|
if use_item {
|
||||||
|
let (key, value) = item.take().unwrap();
|
||||||
|
return visitor.visit_enum(EnumDeserializer::new(
|
||||||
|
key,
|
||||||
|
Some(value)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(Error::custom(format_args!(
|
||||||
|
"no variant of enum {} not found in flattened data",
|
||||||
|
name
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
visitor.visit_map(FlatMapAccess::new(self.0.iter_mut(), None))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_struct<V>(
|
||||||
|
self,
|
||||||
|
_: &'static str,
|
||||||
|
fields: &'static [&'static str],
|
||||||
|
visitor: V
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
visitor.visit_map(FlatMapAccess::new(self.0.iter_mut(), Some(fields)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_newtype_struct<V>(
|
||||||
|
self,
|
||||||
|
_name: &str,
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
visitor.visit_newtype_struct(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_to_deserialize_any! {
|
||||||
|
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||||
|
byte_buf option unit unit_struct seq tuple tuple_struct identifier
|
||||||
|
ignored_any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub struct FlatMapAccess<'a, 'de: 'a, E> {
|
||||||
|
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
|
||||||
|
pending_content: Option<Content<'de>>,
|
||||||
|
fields: Option<&'static [&'static str]>,
|
||||||
|
_marker: PhantomData<E>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> {
|
||||||
|
fn new(
|
||||||
|
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
|
||||||
|
fields: Option<&'static [&'static str]>
|
||||||
|
) -> FlatMapAccess<'a, 'de, E> {
|
||||||
|
FlatMapAccess {
|
||||||
|
iter: iter,
|
||||||
|
pending_content: None,
|
||||||
|
fields: fields,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
|
||||||
|
where E: Error
|
||||||
|
{
|
||||||
|
type Error = E;
|
||||||
|
|
||||||
|
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||||
|
where
|
||||||
|
T: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
while let Some(item) = self.iter.next() {
|
||||||
|
// items in the vector are nulled out when used. So we can only use
|
||||||
|
// an item if it's still filled in and if the field is one we care
|
||||||
|
// about. In case we do not know which fields we want, we take them all.
|
||||||
|
let use_item = match *item {
|
||||||
|
None => false,
|
||||||
|
Some((ref c, _)) => {
|
||||||
|
c.as_str().map_or(self.fields.is_none(), |key| {
|
||||||
|
match self.fields {
|
||||||
|
None => true,
|
||||||
|
Some(fields) if fields.contains(&key) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if use_item {
|
||||||
|
let (key, content) = item.take().unwrap();
|
||||||
|
self.pending_content = Some(content);
|
||||||
|
return seed.deserialize(ContentDeserializer::new(key)).map(Some);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
|
||||||
|
where
|
||||||
|
T: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
match self.pending_content.take() {
|
||||||
|
Some(value) => seed.deserialize(ContentDeserializer::new(value)),
|
||||||
|
None => Err(Error::custom("value is missing")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+300
-13
@@ -11,7 +11,12 @@ use lib::*;
|
|||||||
use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
|
use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use self::content::{SerializeStructVariantAsMapValue, SerializeTupleVariantAsMapValue};
|
use self::content::{
|
||||||
|
SerializeStructVariantAsMapValue,
|
||||||
|
SerializeTupleVariantAsMapValue,
|
||||||
|
ContentSerializer,
|
||||||
|
Content,
|
||||||
|
};
|
||||||
|
|
||||||
/// Used to check that serde(getter) attributes return the expected type.
|
/// Used to check that serde(getter) attributes return the expected type.
|
||||||
/// Not public API.
|
/// Not public API.
|
||||||
@@ -58,10 +63,11 @@ enum Unsupported {
|
|||||||
ByteArray,
|
ByteArray,
|
||||||
Optional,
|
Optional,
|
||||||
Unit,
|
Unit,
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
UnitStruct,
|
||||||
Sequence,
|
Sequence,
|
||||||
Tuple,
|
Tuple,
|
||||||
TupleStruct,
|
TupleStruct,
|
||||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
|
||||||
Enum,
|
Enum,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,10 +82,11 @@ impl Display for Unsupported {
|
|||||||
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
||||||
Unsupported::Optional => formatter.write_str("an optional"),
|
Unsupported::Optional => formatter.write_str("an optional"),
|
||||||
Unsupported::Unit => formatter.write_str("unit"),
|
Unsupported::Unit => formatter.write_str("unit"),
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
Unsupported::UnitStruct => formatter.write_str("unit struct"),
|
||||||
Unsupported::Sequence => formatter.write_str("a sequence"),
|
Unsupported::Sequence => formatter.write_str("a sequence"),
|
||||||
Unsupported::Tuple => formatter.write_str("a tuple"),
|
Unsupported::Tuple => formatter.write_str("a tuple"),
|
||||||
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
||||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
|
||||||
Unsupported::Enum => formatter.write_str("an enum"),
|
Unsupported::Enum => formatter.write_str("an enum"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,7 +466,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Content {
|
pub enum Content {
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
|
|
||||||
U8(u8),
|
U8(u8),
|
||||||
@@ -584,12 +591,12 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContentSerializer<E> {
|
pub struct ContentSerializer<E> {
|
||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> ContentSerializer<E> {
|
impl<E> ContentSerializer<E> {
|
||||||
fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ContentSerializer { error: PhantomData }
|
ContentSerializer { error: PhantomData }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -804,7 +811,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SerializeSeq<E> {
|
pub struct SerializeSeq<E> {
|
||||||
elements: Vec<Content>,
|
elements: Vec<Content>,
|
||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
}
|
}
|
||||||
@@ -830,7 +837,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SerializeTuple<E> {
|
pub struct SerializeTuple<E> {
|
||||||
elements: Vec<Content>,
|
elements: Vec<Content>,
|
||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
}
|
}
|
||||||
@@ -856,7 +863,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SerializeTupleStruct<E> {
|
pub struct SerializeTupleStruct<E> {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
fields: Vec<Content>,
|
fields: Vec<Content>,
|
||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
@@ -883,7 +890,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SerializeTupleVariant<E> {
|
pub struct SerializeTupleVariant<E> {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
variant_index: u32,
|
variant_index: u32,
|
||||||
variant: &'static str,
|
variant: &'static str,
|
||||||
@@ -917,7 +924,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SerializeMap<E> {
|
pub struct SerializeMap<E> {
|
||||||
entries: Vec<(Content, Content)>,
|
entries: Vec<(Content, Content)>,
|
||||||
key: Option<Content>,
|
key: Option<Content>,
|
||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
@@ -967,7 +974,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SerializeStruct<E> {
|
pub struct SerializeStruct<E> {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
fields: Vec<(&'static str, Content)>,
|
fields: Vec<(&'static str, Content)>,
|
||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
@@ -994,7 +1001,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SerializeStructVariant<E> {
|
pub struct SerializeStructVariant<E> {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
variant_index: u32,
|
variant_index: u32,
|
||||||
variant: &'static str,
|
variant: &'static str,
|
||||||
@@ -1028,3 +1035,283 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub struct FlatMapSerializer<'a, M: 'a>(pub &'a mut M);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, M> FlatMapSerializer<'a, M>
|
||||||
|
where
|
||||||
|
M: SerializeMap + 'a
|
||||||
|
{
|
||||||
|
fn bad_type(self, what: Unsupported) -> M::Error {
|
||||||
|
ser::Error::custom(format_args!("can only flatten structs and maps (got {})", what))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, M> Serializer for FlatMapSerializer<'a, M>
|
||||||
|
where M: SerializeMap + 'a
|
||||||
|
{
|
||||||
|
type Ok = ();
|
||||||
|
type Error = M::Error;
|
||||||
|
|
||||||
|
type SerializeSeq = Impossible<Self::Ok, M::Error>;
|
||||||
|
type SerializeTuple = Impossible<Self::Ok, M::Error>;
|
||||||
|
type SerializeTupleStruct = Impossible<Self::Ok, M::Error>;
|
||||||
|
type SerializeMap = FlatMapSerializeMap<'a, M>;
|
||||||
|
type SerializeStruct = FlatMapSerializeStruct<'a, M>;
|
||||||
|
type SerializeTupleVariant = Impossible<Self::Ok, M::Error>;
|
||||||
|
type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>;
|
||||||
|
|
||||||
|
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Boolean))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Integer))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Integer))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Integer))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Integer))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Integer))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Integer))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Integer))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Integer))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Float))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Float))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Char))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::String))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::ByteArray))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Optional))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
Err(self.bad_type(Unsupported::Optional))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Unit))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::UnitStruct))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit_variant(
|
||||||
|
self,
|
||||||
|
_: &'static str,
|
||||||
|
_: u32,
|
||||||
|
_: &'static str,
|
||||||
|
) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Enum))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_newtype_struct<T: ?Sized>(
|
||||||
|
self,
|
||||||
|
_: &'static str,
|
||||||
|
value: &T,
|
||||||
|
) -> Result<Self::Ok, Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
value.serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_newtype_variant<T: ?Sized>(
|
||||||
|
self,
|
||||||
|
_: &'static str,
|
||||||
|
_: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
value: &T,
|
||||||
|
) -> Result<Self::Ok, Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
try!(self.0.serialize_key(variant));
|
||||||
|
self.0.serialize_value(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Sequence))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Tuple))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_struct(
|
||||||
|
self,
|
||||||
|
_: &'static str,
|
||||||
|
_: usize,
|
||||||
|
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::TupleStruct))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_variant(
|
||||||
|
self,
|
||||||
|
_: &'static str,
|
||||||
|
_: u32,
|
||||||
|
_: &'static str,
|
||||||
|
_: usize,
|
||||||
|
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||||
|
Err(self.bad_type(Unsupported::Enum))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||||
|
Ok(FlatMapSerializeMap(self.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct(
|
||||||
|
self,
|
||||||
|
_: &'static str,
|
||||||
|
_: usize,
|
||||||
|
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||||
|
Ok(FlatMapSerializeStruct(self.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_variant(
|
||||||
|
self,
|
||||||
|
_: &'static str,
|
||||||
|
_: u32,
|
||||||
|
inner_variant: &'static str,
|
||||||
|
_: usize,
|
||||||
|
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||||
|
try!(self.0.serialize_key(inner_variant));
|
||||||
|
Ok(FlatMapSerializeStructVariantAsMapValue::new(self.0, inner_variant))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub struct FlatMapSerializeMap<'a, M: 'a>(&'a mut M);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, M> ser::SerializeMap for FlatMapSerializeMap<'a, M>
|
||||||
|
where M: SerializeMap + 'a
|
||||||
|
{
|
||||||
|
type Ok = ();
|
||||||
|
type Error = M::Error;
|
||||||
|
|
||||||
|
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_key(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_value(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub struct FlatMapSerializeStruct<'a, M: 'a>(&'a mut M);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, M> ser::SerializeStruct for FlatMapSerializeStruct<'a, M>
|
||||||
|
where M: SerializeMap + 'a
|
||||||
|
{
|
||||||
|
type Ok = ();
|
||||||
|
type Error = M::Error;
|
||||||
|
|
||||||
|
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_entry(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub struct FlatMapSerializeStructVariantAsMapValue<'a, M: 'a> {
|
||||||
|
map: &'a mut M,
|
||||||
|
name: &'static str,
|
||||||
|
fields: Vec<(&'static str, Content)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, M> FlatMapSerializeStructVariantAsMapValue<'a, M>
|
||||||
|
where M: SerializeMap + 'a
|
||||||
|
{
|
||||||
|
fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> {
|
||||||
|
FlatMapSerializeStructVariantAsMapValue {
|
||||||
|
map: map,
|
||||||
|
name: name,
|
||||||
|
fields: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapValue<'a, M>
|
||||||
|
where M: SerializeMap + 'a
|
||||||
|
{
|
||||||
|
type Ok = ();
|
||||||
|
type Error = M::Error;
|
||||||
|
|
||||||
|
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
let value = try!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||||
|
self.fields.push((key, value));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<(), Self::Error> {
|
||||||
|
try!(self.map.serialize_value(&Content::Struct(self.name, self.fields)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -351,6 +351,7 @@ deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwne
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
|
#[allow(deprecated)]
|
||||||
impl<T> Serialize for NonZero<T>
|
impl<T> Serialize for NonZero<T>
|
||||||
where
|
where
|
||||||
T: Serialize + Zeroable + Clone,
|
T: Serialize + Zeroable + Clone,
|
||||||
@@ -363,6 +364,32 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! nonzero_integers {
|
||||||
|
( $( $T: ident, )+ ) => {
|
||||||
|
$(
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
|
impl Serialize for $T {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
self.get().serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nonzero_integers! {
|
||||||
|
// Not including signed NonZeroI* since they might be removed
|
||||||
|
NonZeroU8,
|
||||||
|
NonZeroU16,
|
||||||
|
NonZeroU32,
|
||||||
|
NonZeroU64,
|
||||||
|
// FIXME: https://github.com/serde-rs/serde/issues/1136 NonZeroU128,
|
||||||
|
NonZeroUsize,
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Serialize for Cell<T>
|
impl<T> Serialize for Cell<T>
|
||||||
where
|
where
|
||||||
T: Serialize + Copy,
|
T: Serialize + Copy,
|
||||||
|
|||||||
@@ -93,7 +93,8 @@
|
|||||||
//! - Path
|
//! - Path
|
||||||
//! - PathBuf
|
//! - PathBuf
|
||||||
//! - Range\<T\>
|
//! - Range\<T\>
|
||||||
//! - NonZero\<T\> (unstable)
|
//! - NonZero\<T\> (unstable, deprecated)
|
||||||
|
//! - num::NonZero* (unstable)
|
||||||
//! - **Net types**:
|
//! - **Net types**:
|
||||||
//! - IpAddr
|
//! - IpAddr
|
||||||
//! - Ipv4Addr
|
//! - Ipv4Addr
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.32" # remember to update html_root_url
|
version = "1.0.36" # remember to update html_root_url
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
||||||
@@ -25,7 +25,7 @@ proc-macro = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "0.2"
|
proc-macro2 = "0.2"
|
||||||
quote = "0.4"
|
quote = "0.4"
|
||||||
serde_derive_internals = { version = "=0.20.1", default-features = false, path = "../serde_derive_internals" }
|
serde_derive_internals = { version = "=0.22.2", default-features = false, path = "../serde_derive_internals" }
|
||||||
syn = { version = "0.12", features = ["visit"] }
|
syn = { version = "0.12", features = ["visit"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
+303
-46
@@ -268,7 +268,11 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<St
|
|||||||
|
|
||||||
let code = match cont.data {
|
let code = match cont.data {
|
||||||
Data::Struct(Style::Struct, ref fields) => {
|
Data::Struct(Style::Struct, ref fields) => {
|
||||||
deserialize_struct_in_place(None, params, fields, &cont.attrs, None)
|
if let Some(code) = deserialize_struct_in_place(None, params, fields, &cont.attrs, None) {
|
||||||
|
code
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => {
|
Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => {
|
||||||
deserialize_tuple_in_place(None, params, fields, &cont.attrs, None)
|
deserialize_tuple_in_place(None, params, fields, &cont.attrs, None)
|
||||||
@@ -345,6 +349,8 @@ fn deserialize_tuple(
|
|||||||
split_with_de_lifetime(params);
|
split_with_de_lifetime(params);
|
||||||
let delife = params.borrowed.de_lifetime();
|
let delife = params.borrowed.de_lifetime();
|
||||||
|
|
||||||
|
assert!(!cattrs.has_flatten());
|
||||||
|
|
||||||
// If there are getters (implying private fields), construct the local type
|
// If there are getters (implying private fields), construct the local type
|
||||||
// and use an `Into` conversion to get the remote type. If there are no
|
// and use an `Into` conversion to get the remote type. If there are no
|
||||||
// getters then construct the target type directly.
|
// getters then construct the target type directly.
|
||||||
@@ -440,6 +446,8 @@ fn deserialize_tuple_in_place(
|
|||||||
split_with_de_lifetime(params);
|
split_with_de_lifetime(params);
|
||||||
let delife = params.borrowed.de_lifetime();
|
let delife = params.borrowed.de_lifetime();
|
||||||
|
|
||||||
|
assert!(!cattrs.has_flatten());
|
||||||
|
|
||||||
let is_enum = variant_ident.is_some();
|
let is_enum = variant_ident.is_some();
|
||||||
let expecting = match variant_ident {
|
let expecting = match variant_ident {
|
||||||
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
|
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
|
||||||
@@ -522,6 +530,8 @@ fn deserialize_seq(
|
|||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let vars = (0..fields.len()).map(field_i as fn(_) -> _);
|
let vars = (0..fields.len()).map(field_i as fn(_) -> _);
|
||||||
|
|
||||||
|
// XXX: do we need an error for flattening here?
|
||||||
|
|
||||||
let deserialized_count = fields
|
let deserialized_count = fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|field| !field.attrs.skip_deserializing())
|
.filter(|field| !field.attrs.skip_deserializing())
|
||||||
@@ -613,6 +623,8 @@ fn deserialize_seq_in_place(
|
|||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let vars = (0..fields.len()).map(field_i as fn(_) -> _);
|
let vars = (0..fields.len()).map(field_i as fn(_) -> _);
|
||||||
|
|
||||||
|
// XXX: do we need an error for flattening here?
|
||||||
|
|
||||||
let deserialized_count = fields
|
let deserialized_count = fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|field| !field.attrs.skip_deserializing())
|
.filter(|field| !field.attrs.skip_deserializing())
|
||||||
@@ -793,10 +805,13 @@ fn deserialize_struct(
|
|||||||
|
|
||||||
let visit_seq = Stmts(deserialize_seq(&type_path, params, fields, true, cattrs));
|
let visit_seq = Stmts(deserialize_seq(&type_path, params, fields, true, cattrs));
|
||||||
|
|
||||||
let (field_visitor, fields_stmt, visit_map) =
|
let (field_visitor, fields_stmt, visit_map) = if cattrs.has_flatten() {
|
||||||
deserialize_struct_visitor(&type_path, params, fields, cattrs);
|
deserialize_struct_as_map_visitor(&type_path, params, fields, cattrs)
|
||||||
|
} else {
|
||||||
|
deserialize_struct_as_struct_visitor(&type_path, params, fields, cattrs)
|
||||||
|
};
|
||||||
let field_visitor = Stmts(field_visitor);
|
let field_visitor = Stmts(field_visitor);
|
||||||
let fields_stmt = Stmts(fields_stmt);
|
let fields_stmt = fields_stmt.map(Stmts);
|
||||||
let visit_map = Stmts(visit_map);
|
let visit_map = Stmts(visit_map);
|
||||||
|
|
||||||
let visitor_expr = quote! {
|
let visitor_expr = quote! {
|
||||||
@@ -813,6 +828,10 @@ fn deserialize_struct(
|
|||||||
quote! {
|
quote! {
|
||||||
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
|
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
|
||||||
}
|
}
|
||||||
|
} else if cattrs.has_flatten() {
|
||||||
|
quote! {
|
||||||
|
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let type_name = cattrs.name().deserialize_name();
|
let type_name = cattrs.name().deserialize_name();
|
||||||
quote! {
|
quote! {
|
||||||
@@ -827,10 +846,10 @@ fn deserialize_struct(
|
|||||||
quote!(mut __seq)
|
quote!(mut __seq)
|
||||||
};
|
};
|
||||||
|
|
||||||
// untagged struct variants do not get a visit_seq method
|
// untagged struct variants do not get a visit_seq method. The same applies to structs that
|
||||||
|
// only have a map representation.
|
||||||
let visit_seq = match *untagged {
|
let visit_seq = match *untagged {
|
||||||
Untagged::Yes => None,
|
Untagged::No if !cattrs.has_flatten() => Some(quote! {
|
||||||
Untagged::No => Some(quote! {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||||
where __A: _serde::de::SeqAccess<#delife>
|
where __A: _serde::de::SeqAccess<#delife>
|
||||||
@@ -838,6 +857,7 @@ fn deserialize_struct(
|
|||||||
#visit_seq
|
#visit_seq
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
@@ -878,9 +898,15 @@ fn deserialize_struct_in_place(
|
|||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
deserializer: Option<Tokens>,
|
deserializer: Option<Tokens>,
|
||||||
) -> Fragment {
|
) -> Option<Fragment> {
|
||||||
let is_enum = variant_ident.is_some();
|
let is_enum = variant_ident.is_some();
|
||||||
|
|
||||||
|
// for now we do not support in_place deserialization for structs that
|
||||||
|
// are represented as map.
|
||||||
|
if cattrs.has_flatten() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let this = ¶ms.this;
|
let this = ¶ms.this;
|
||||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||||
split_with_de_lifetime(params);
|
split_with_de_lifetime(params);
|
||||||
@@ -893,8 +919,9 @@ fn deserialize_struct_in_place(
|
|||||||
|
|
||||||
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs));
|
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs));
|
||||||
|
|
||||||
let (field_visitor, fields_stmt, visit_map) =
|
let (field_visitor, fields_stmt, visit_map) = deserialize_struct_as_struct_in_place_visitor(
|
||||||
deserialize_struct_in_place_visitor(params, fields, cattrs);
|
params, fields, cattrs);
|
||||||
|
|
||||||
let field_visitor = Stmts(field_visitor);
|
let field_visitor = Stmts(field_visitor);
|
||||||
let fields_stmt = Stmts(fields_stmt);
|
let fields_stmt = Stmts(fields_stmt);
|
||||||
let visit_map = Stmts(visit_map);
|
let visit_map = Stmts(visit_map);
|
||||||
@@ -940,7 +967,7 @@ fn deserialize_struct_in_place(
|
|||||||
let in_place_ty_generics = de_ty_generics.in_place();
|
let in_place_ty_generics = de_ty_generics.in_place();
|
||||||
let place_life = place_lifetime();
|
let place_life = place_lifetime();
|
||||||
|
|
||||||
quote_block! {
|
Some(quote_block! {
|
||||||
#field_visitor
|
#field_visitor
|
||||||
|
|
||||||
struct __Visitor #in_place_impl_generics #where_clause {
|
struct __Visitor #in_place_impl_generics #where_clause {
|
||||||
@@ -968,7 +995,7 @@ fn deserialize_struct_in_place(
|
|||||||
#fields_stmt
|
#fields_stmt
|
||||||
|
|
||||||
#dispatch
|
#dispatch
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_enum(
|
fn deserialize_enum(
|
||||||
@@ -1688,12 +1715,16 @@ fn deserialize_untagged_newtype_variant(
|
|||||||
fn deserialize_generated_identifier(
|
fn deserialize_generated_identifier(
|
||||||
fields: &[(String, Ident)],
|
fields: &[(String, Ident)],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
is_variant: bool,
|
is_variant: bool
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let this = quote!(__Field);
|
let this = quote!(__Field);
|
||||||
let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident)| ident).collect();
|
let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident)| ident).collect();
|
||||||
|
|
||||||
let (ignore_variant, fallthrough) = if is_variant || cattrs.deny_unknown_fields() {
|
let (ignore_variant, fallthrough) = if 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))
|
||||||
|
} else if is_variant || cattrs.deny_unknown_fields() {
|
||||||
(None, None)
|
(None, None)
|
||||||
} else {
|
} else {
|
||||||
let ignore_variant = quote!(__ignore,);
|
let ignore_variant = quote!(__ignore,);
|
||||||
@@ -1706,11 +1737,18 @@ fn deserialize_generated_identifier(
|
|||||||
fields,
|
fields,
|
||||||
is_variant,
|
is_variant,
|
||||||
fallthrough,
|
fallthrough,
|
||||||
|
cattrs.has_flatten(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let lifetime = if cattrs.has_flatten() {
|
||||||
|
Some(quote!(<'de>))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
enum __Field {
|
enum __Field #lifetime {
|
||||||
#(#field_idents,)*
|
#(#field_idents,)*
|
||||||
#ignore_variant
|
#ignore_variant
|
||||||
}
|
}
|
||||||
@@ -1718,12 +1756,12 @@ fn deserialize_generated_identifier(
|
|||||||
struct __FieldVisitor;
|
struct __FieldVisitor;
|
||||||
|
|
||||||
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
|
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
|
||||||
type Value = __Field;
|
type Value = __Field #lifetime;
|
||||||
|
|
||||||
#visitor_impl
|
#visitor_impl
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> _serde::Deserialize<'de> for __Field {
|
impl<'de> _serde::Deserialize<'de> for __Field #lifetime {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
|
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
|
||||||
where __D: _serde::Deserializer<'de>
|
where __D: _serde::Deserializer<'de>
|
||||||
@@ -1804,6 +1842,7 @@ fn deserialize_custom_identifier(
|
|||||||
&names_idents,
|
&names_idents,
|
||||||
is_variant,
|
is_variant,
|
||||||
fallthrough,
|
fallthrough,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
@@ -1833,9 +1872,12 @@ fn deserialize_identifier(
|
|||||||
fields: &[(String, Ident)],
|
fields: &[(String, Ident)],
|
||||||
is_variant: bool,
|
is_variant: bool,
|
||||||
fallthrough: Option<Tokens>,
|
fallthrough: Option<Tokens>,
|
||||||
|
collect_other_fields: bool
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let field_strs = fields.iter().map(|&(ref name, _)| name);
|
let field_strs = fields.iter().map(|&(ref name, _)| name);
|
||||||
|
let field_borrowed_strs = fields.iter().map(|&(ref name, _)| name);
|
||||||
let field_bytes = fields.iter().map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
|
let field_bytes = fields.iter().map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
|
||||||
|
let field_borrowed_bytes = fields.iter().map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
|
||||||
|
|
||||||
let constructors: &Vec<_> = &fields
|
let constructors: &Vec<_> = &fields
|
||||||
.iter()
|
.iter()
|
||||||
@@ -1852,28 +1894,129 @@ fn deserialize_identifier(
|
|||||||
|
|
||||||
let variant_indices = 0u64..;
|
let variant_indices = 0u64..;
|
||||||
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
|
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
|
||||||
let visit_index = quote! {
|
let visit_other = if collect_other_fields {
|
||||||
fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
|
Some(quote! {
|
||||||
where __E: _serde::de::Error
|
fn visit_bool<__E>(self, __value: bool) -> Result<Self::Value, __E>
|
||||||
{
|
where __E: _serde::de::Error
|
||||||
match __value {
|
{
|
||||||
#(
|
Ok(__Field::__other(_serde::private::de::Content::Bool(__value)))
|
||||||
#variant_indices => _serde::export::Ok(#constructors),
|
|
||||||
)*
|
|
||||||
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
|
||||||
_serde::de::Unexpected::Unsigned(__value),
|
|
||||||
&#fallthrough_msg))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
fn visit_i8<__E>(self, __value: i8) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::I8(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_i16<__E>(self, __value: i16) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::I16(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_i32<__E>(self, __value: i32) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::I32(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_i64<__E>(self, __value: i64) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::I64(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u8<__E>(self, __value: u8) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::U8(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u16<__E>(self, __value: u16) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::U16(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u32<__E>(self, __value: u32) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::U32(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u64<__E>(self, __value: u64) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::U64(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_f32<__E>(self, __value: f32) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::F32(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_f64<__E>(self, __value: f64) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::F64(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_char<__E>(self, __value: char) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::Char(__value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_unit<__E>(self) -> Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
Ok(__Field::__other(_serde::private::de::Content::Unit))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Some(quote! {
|
||||||
|
fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
match __value {
|
||||||
|
#(
|
||||||
|
#variant_indices => _serde::export::Ok(#constructors),
|
||||||
|
)*
|
||||||
|
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
||||||
|
_serde::de::Unexpected::Unsigned(__value),
|
||||||
|
&#fallthrough_msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let bytes_to_str = if fallthrough.is_some() {
|
let bytes_to_str = if fallthrough.is_some() || collect_other_fields {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let conversion = quote! {
|
Some(quote! {
|
||||||
let __value = &_serde::export::from_utf8_lossy(__value);
|
let __value = &_serde::export::from_utf8_lossy(__value);
|
||||||
};
|
})
|
||||||
Some(conversion)
|
};
|
||||||
|
|
||||||
|
let (value_as_str_content, value_as_borrowed_str_content,
|
||||||
|
value_as_bytes_content, value_as_borrowed_bytes_content) = if !collect_other_fields {
|
||||||
|
(None, None, None, None)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
Some(quote! {
|
||||||
|
let __value = _serde::private::de::Content::String(__value.to_string());
|
||||||
|
}),
|
||||||
|
Some(quote! {
|
||||||
|
let __value = _serde::private::de::Content::Str(__value);
|
||||||
|
}),
|
||||||
|
Some(quote! {
|
||||||
|
let __value = _serde::private::de::Content::ByteBuf(__value.to_vec());
|
||||||
|
}),
|
||||||
|
Some(quote! {
|
||||||
|
let __value = _serde::private::de::Content::Bytes(__value);
|
||||||
|
})
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let fallthrough_arm = if let Some(fallthrough) = fallthrough {
|
let fallthrough_arm = if let Some(fallthrough) = fallthrough {
|
||||||
@@ -1893,7 +2036,7 @@ fn deserialize_identifier(
|
|||||||
_serde::export::Formatter::write_str(formatter, #expecting)
|
_serde::export::Formatter::write_str(formatter, #expecting)
|
||||||
}
|
}
|
||||||
|
|
||||||
#visit_index
|
#visit_other
|
||||||
|
|
||||||
fn visit_str<__E>(self, __value: &str) -> _serde::export::Result<Self::Value, __E>
|
fn visit_str<__E>(self, __value: &str) -> _serde::export::Result<Self::Value, __E>
|
||||||
where __E: _serde::de::Error
|
where __E: _serde::de::Error
|
||||||
@@ -1902,7 +2045,39 @@ fn deserialize_identifier(
|
|||||||
#(
|
#(
|
||||||
#field_strs => _serde::export::Ok(#constructors),
|
#field_strs => _serde::export::Ok(#constructors),
|
||||||
)*
|
)*
|
||||||
_ => #fallthrough_arm
|
_ => {
|
||||||
|
#value_as_str_content
|
||||||
|
#fallthrough_arm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::export::Result<Self::Value, __E>
|
||||||
|
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<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
match __value {
|
||||||
|
#(
|
||||||
|
#field_borrowed_bytes => _serde::export::Ok(#constructors),
|
||||||
|
)*
|
||||||
|
_ => {
|
||||||
|
#bytes_to_str
|
||||||
|
#value_as_borrowed_bytes_content
|
||||||
|
#fallthrough_arm
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1915,6 +2090,7 @@ fn deserialize_identifier(
|
|||||||
)*
|
)*
|
||||||
_ => {
|
_ => {
|
||||||
#bytes_to_str
|
#bytes_to_str
|
||||||
|
#value_as_bytes_content
|
||||||
#fallthrough_arm
|
#fallthrough_arm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1922,12 +2098,14 @@ fn deserialize_identifier(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_struct_visitor(
|
fn deserialize_struct_as_struct_visitor(
|
||||||
struct_path: &Tokens,
|
struct_path: &Tokens,
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
) -> (Fragment, Fragment, Fragment) {
|
) -> (Fragment, Option<Fragment>, Fragment) {
|
||||||
|
assert!(!cattrs.has_flatten());
|
||||||
|
|
||||||
let field_names_idents: Vec<_> = fields
|
let field_names_idents: Vec<_> = fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@@ -1946,7 +2124,27 @@ fn deserialize_struct_visitor(
|
|||||||
|
|
||||||
let visit_map = deserialize_map(struct_path, params, fields, cattrs);
|
let visit_map = deserialize_map(struct_path, params, fields, cattrs);
|
||||||
|
|
||||||
(field_visitor, fields_stmt, visit_map)
|
(field_visitor, Some(fields_stmt), visit_map)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_struct_as_map_visitor(
|
||||||
|
struct_path: &Tokens,
|
||||||
|
params: &Parameters,
|
||||||
|
fields: &[Field],
|
||||||
|
cattrs: &attr::Container,
|
||||||
|
) -> (Fragment, Option<Fragment>, Fragment) {
|
||||||
|
let field_names_idents: Vec<_> = fields
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
|
||||||
|
.map(|(i, field)| (field.attrs.name().deserialize_name(), field_i(i)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false);
|
||||||
|
|
||||||
|
let visit_map = deserialize_map(struct_path, params, fields, cattrs);
|
||||||
|
|
||||||
|
(field_visitor, None, visit_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_map(
|
fn deserialize_map(
|
||||||
@@ -1965,7 +2163,7 @@ fn deserialize_map(
|
|||||||
// Declare each field that will be deserialized.
|
// Declare each field that will be deserialized.
|
||||||
let let_values = fields_names
|
let let_values = fields_names
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
|
||||||
.map(|&(field, ref name)| {
|
.map(|&(field, ref name)| {
|
||||||
let field_ty = &field.ty;
|
let field_ty = &field.ty;
|
||||||
quote! {
|
quote! {
|
||||||
@@ -1973,10 +2171,22 @@ fn deserialize_map(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Collect contents for flatten fields into a buffer
|
||||||
|
let let_collect = if cattrs.has_flatten() {
|
||||||
|
Some(quote! {
|
||||||
|
let mut __collect = Vec::<Option<(
|
||||||
|
_serde::private::de::Content,
|
||||||
|
_serde::private::de::Content
|
||||||
|
)>>::new();
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Match arms to extract a value for a field.
|
// Match arms to extract a value for a field.
|
||||||
let value_arms = fields_names
|
let value_arms = fields_names
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
|
||||||
.map(|&(field, ref name)| {
|
.map(|&(field, ref name)| {
|
||||||
let deser_name = field.attrs.name().deserialize_name();
|
let deser_name = field.attrs.name().deserialize_name();
|
||||||
|
|
||||||
@@ -2008,7 +2218,15 @@ fn deserialize_map(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Visit ignored values to consume them
|
// Visit ignored values to consume them
|
||||||
let ignored_arm = if cattrs.deny_unknown_fields() {
|
let ignored_arm = if cattrs.has_flatten() {
|
||||||
|
Some(quote! {
|
||||||
|
__Field::__other(__name) => {
|
||||||
|
__collect.push(Some((
|
||||||
|
__name,
|
||||||
|
try!(_serde::de::MapAccess::next_value(&mut __map)))));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if cattrs.deny_unknown_fields() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
@@ -2038,7 +2256,7 @@ fn deserialize_map(
|
|||||||
|
|
||||||
let extract_values = fields_names
|
let extract_values = fields_names
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
|
||||||
.map(|&(field, ref name)| {
|
.map(|&(field, ref name)| {
|
||||||
let missing_expr = Match(expr_is_missing(field, cattrs));
|
let missing_expr = Match(expr_is_missing(field, cattrs));
|
||||||
|
|
||||||
@@ -2050,6 +2268,35 @@ fn deserialize_map(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let extract_collected = fields_names
|
||||||
|
.iter()
|
||||||
|
.filter(|&&(field, _)| field.attrs.flatten())
|
||||||
|
.map(|&(field, ref name)| {
|
||||||
|
let field_ty = field.ty;
|
||||||
|
quote! {
|
||||||
|
let #name: #field_ty = try!(_serde::de::Deserialize::deserialize(
|
||||||
|
_serde::private::de::FlatMapDeserializer(
|
||||||
|
&mut __collect,
|
||||||
|
_serde::export::PhantomData)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let collected_deny_unknown_fields = if cattrs.has_flatten() && cattrs.deny_unknown_fields() {
|
||||||
|
Some(quote! {
|
||||||
|
if let Some(Some((__key, _))) = __collect.into_iter().filter(|x| x.is_some()).next() {
|
||||||
|
if let Some(__key) = __key.as_str() {
|
||||||
|
return _serde::export::Err(
|
||||||
|
_serde::de::Error::custom(format_args!("unknown field `{}`", &__key)));
|
||||||
|
} else {
|
||||||
|
return _serde::export::Err(
|
||||||
|
_serde::de::Error::custom(format_args!("unexpected map key")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let result = fields_names.iter().map(|&(field, ref name)| {
|
let result = fields_names.iter().map(|&(field, ref name)| {
|
||||||
let ident = field.ident.expect("struct contains unnamed fields");
|
let ident = field.ident.expect("struct contains unnamed fields");
|
||||||
if field.attrs.skip_deserializing() {
|
if field.attrs.skip_deserializing() {
|
||||||
@@ -2085,22 +2332,30 @@ fn deserialize_map(
|
|||||||
quote_block! {
|
quote_block! {
|
||||||
#(#let_values)*
|
#(#let_values)*
|
||||||
|
|
||||||
|
#let_collect
|
||||||
|
|
||||||
#match_keys
|
#match_keys
|
||||||
|
|
||||||
#let_default
|
#let_default
|
||||||
|
|
||||||
#(#extract_values)*
|
#(#extract_values)*
|
||||||
|
|
||||||
|
#(#extract_collected)*
|
||||||
|
|
||||||
|
#collected_deny_unknown_fields
|
||||||
|
|
||||||
_serde::export::Ok(#result)
|
_serde::export::Ok(#result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "deserialize_in_place")]
|
#[cfg(feature = "deserialize_in_place")]
|
||||||
fn deserialize_struct_in_place_visitor(
|
fn deserialize_struct_as_struct_in_place_visitor(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
) -> (Fragment, Fragment, Fragment) {
|
) -> (Fragment, Fragment, Fragment) {
|
||||||
|
assert!(!cattrs.has_flatten());
|
||||||
|
|
||||||
let field_names_idents: Vec<_> = fields
|
let field_names_idents: Vec<_> = fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@@ -2128,6 +2383,8 @@ fn deserialize_map_in_place(
|
|||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
|
assert!(!cattrs.has_flatten());
|
||||||
|
|
||||||
// Create the field names for the fields.
|
// Create the field names for the fields.
|
||||||
let fields_names: Vec<_> = fields
|
let fields_names: Vec<_> = fields
|
||||||
.iter()
|
.iter()
|
||||||
@@ -2273,7 +2530,7 @@ fn field_i(i: usize) -> Ident {
|
|||||||
fn wrap_deserialize_with(
|
fn wrap_deserialize_with(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
value_ty: &Tokens,
|
value_ty: &Tokens,
|
||||||
deserialize_with: &syn::Path,
|
deserialize_with: &syn::ExprPath,
|
||||||
) -> (Tokens, Tokens) {
|
) -> (Tokens, Tokens) {
|
||||||
let this = ¶ms.this;
|
let this = ¶ms.this;
|
||||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||||
@@ -2308,7 +2565,7 @@ fn wrap_deserialize_with(
|
|||||||
fn wrap_deserialize_field_with(
|
fn wrap_deserialize_field_with(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
field_ty: &syn::Type,
|
field_ty: &syn::Type,
|
||||||
deserialize_with: &syn::Path,
|
deserialize_with: &syn::ExprPath,
|
||||||
) -> (Tokens, Tokens) {
|
) -> (Tokens, Tokens) {
|
||||||
wrap_deserialize_with(params, "e!(#field_ty), deserialize_with)
|
wrap_deserialize_with(params, "e!(#field_ty), deserialize_with)
|
||||||
}
|
}
|
||||||
@@ -2316,7 +2573,7 @@ fn wrap_deserialize_field_with(
|
|||||||
fn wrap_deserialize_variant_with(
|
fn wrap_deserialize_variant_with(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
variant: &Variant,
|
variant: &Variant,
|
||||||
deserialize_with: &syn::Path,
|
deserialize_with: &syn::ExprPath,
|
||||||
) -> (Tokens, Tokens, Tokens) {
|
) -> (Tokens, Tokens, Tokens) {
|
||||||
let this = ¶ms.this;
|
let this = ¶ms.this;
|
||||||
let variant_ident = &variant.ident;
|
let variant_ident = &variant.ident;
|
||||||
|
|||||||
@@ -22,11 +22,11 @@
|
|||||||
//!
|
//!
|
||||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.32")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.36")]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(enum_variant_names, redundant_field_names,
|
#![cfg_attr(feature = "cargo-clippy", allow(enum_variant_names, redundant_field_names,
|
||||||
too_many_arguments, used_underscore_binding))]
|
too_many_arguments, used_underscore_binding))]
|
||||||
// The `quote!` macro requires deep recursion.
|
// The `quote!` macro requires deep recursion.
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "512"]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate quote;
|
extern crate quote;
|
||||||
|
|||||||
+82
-17
@@ -245,6 +245,14 @@ fn serialize_tuple_struct(
|
|||||||
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
||||||
assert!(fields.len() as u64 <= u64::from(u32::MAX));
|
assert!(fields.len() as u64 <= u64::from(u32::MAX));
|
||||||
|
|
||||||
|
if cattrs.has_flatten() {
|
||||||
|
serialize_struct_as_map(params, fields, cattrs)
|
||||||
|
} else {
|
||||||
|
serialize_struct_as_struct(params, fields, cattrs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_as_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
||||||
let serialize_fields = serialize_struct_visitor(
|
let serialize_fields = serialize_struct_visitor(
|
||||||
fields,
|
fields,
|
||||||
params,
|
params,
|
||||||
@@ -279,6 +287,44 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_as_map(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
||||||
|
let serialize_fields = serialize_struct_visitor(
|
||||||
|
fields,
|
||||||
|
params,
|
||||||
|
false,
|
||||||
|
&StructTrait::SerializeMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut serialized_fields = fields
|
||||||
|
.iter()
|
||||||
|
.filter(|&field| !field.attrs.skip_serializing())
|
||||||
|
.peekable();
|
||||||
|
|
||||||
|
let let_mut = mut_if(serialized_fields.peek().is_some());
|
||||||
|
|
||||||
|
let len = if cattrs.has_flatten() {
|
||||||
|
quote!(_serde::export::None)
|
||||||
|
} else {
|
||||||
|
let len = serialized_fields
|
||||||
|
.map(|field| match field.attrs.skip_serializing_if() {
|
||||||
|
None => quote!(1),
|
||||||
|
Some(path) => {
|
||||||
|
let ident = field.ident.expect("struct has unnamed fields");
|
||||||
|
let field_expr = get_member(params, field, &Member::Named(ident));
|
||||||
|
quote!(if #path(#field_expr) { 0 } else { 1 })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
|
||||||
|
quote!(_serde::export::Some(#len))
|
||||||
|
};
|
||||||
|
|
||||||
|
quote_block! {
|
||||||
|
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len));
|
||||||
|
#(#serialize_fields)*
|
||||||
|
_serde::ser::SerializeMap::end(__serde_state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment {
|
fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment {
|
||||||
assert!(variants.len() as u64 <= u64::from(u32::MAX));
|
assert!(variants.len() as u64 <= u64::from(u32::MAX));
|
||||||
|
|
||||||
@@ -859,6 +905,7 @@ fn serialize_struct_visitor(
|
|||||||
.filter(|&field| !field.attrs.skip_serializing())
|
.filter(|&field| !field.attrs.skip_serializing())
|
||||||
.map(|field| {
|
.map(|field| {
|
||||||
let field_ident = field.ident.expect("struct has unnamed field");
|
let field_ident = field.ident.expect("struct has unnamed field");
|
||||||
|
|
||||||
let mut field_expr = if is_enum {
|
let mut field_expr = if is_enum {
|
||||||
quote!(#field_ident)
|
quote!(#field_ident)
|
||||||
} else {
|
} else {
|
||||||
@@ -877,20 +924,33 @@ fn serialize_struct_visitor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let span = Span::def_site().located_at(field.original.span());
|
let span = Span::def_site().located_at(field.original.span());
|
||||||
let func = struct_trait.serialize_field(span);
|
let ser = if field.attrs.flatten() {
|
||||||
let ser = quote! {
|
quote! {
|
||||||
try!(#func(&mut __serde_state, #key_expr, #field_expr));
|
try!(_serde::Serialize::serialize(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let func = struct_trait.serialize_field(span);
|
||||||
|
quote! {
|
||||||
|
try!(#func(&mut __serde_state, #key_expr, #field_expr));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match skip {
|
match skip {
|
||||||
None => ser,
|
None => ser,
|
||||||
Some(skip) => {
|
Some(skip) => {
|
||||||
let skip_func = struct_trait.skip_field(span);
|
if let Some(skip_func) = struct_trait.skip_field(span) {
|
||||||
quote! {
|
quote! {
|
||||||
if !#skip {
|
if !#skip {
|
||||||
#ser
|
#ser
|
||||||
} else {
|
} else {
|
||||||
try!(#skip_func(&mut __serde_state, #key_expr));
|
try!(#skip_func(&mut __serde_state, #key_expr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
if !#skip {
|
||||||
|
#ser
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -902,7 +962,7 @@ fn serialize_struct_visitor(
|
|||||||
fn wrap_serialize_field_with(
|
fn wrap_serialize_field_with(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
field_ty: &syn::Type,
|
field_ty: &syn::Type,
|
||||||
serialize_with: &syn::Path,
|
serialize_with: &syn::ExprPath,
|
||||||
field_expr: &Tokens,
|
field_expr: &Tokens,
|
||||||
) -> Tokens {
|
) -> Tokens {
|
||||||
wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)])
|
wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)])
|
||||||
@@ -910,7 +970,7 @@ fn wrap_serialize_field_with(
|
|||||||
|
|
||||||
fn wrap_serialize_variant_with(
|
fn wrap_serialize_variant_with(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
serialize_with: &syn::Path,
|
serialize_with: &syn::ExprPath,
|
||||||
variant: &Variant,
|
variant: &Variant,
|
||||||
) -> Tokens {
|
) -> Tokens {
|
||||||
let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect();
|
let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect();
|
||||||
@@ -935,7 +995,7 @@ fn wrap_serialize_variant_with(
|
|||||||
|
|
||||||
fn wrap_serialize_with(
|
fn wrap_serialize_with(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
serialize_with: &syn::Path,
|
serialize_with: &syn::ExprPath,
|
||||||
field_tys: &[&syn::Type],
|
field_tys: &[&syn::Type],
|
||||||
field_exprs: &[Tokens],
|
field_exprs: &[Tokens],
|
||||||
) -> Tokens {
|
) -> Tokens {
|
||||||
@@ -1011,6 +1071,7 @@ fn get_member(params: &Parameters, field: &Field, member: &Member) -> Tokens {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum StructTrait {
|
enum StructTrait {
|
||||||
|
SerializeMap,
|
||||||
SerializeStruct,
|
SerializeStruct,
|
||||||
SerializeStructVariant,
|
SerializeStructVariant,
|
||||||
}
|
}
|
||||||
@@ -1018,6 +1079,9 @@ enum StructTrait {
|
|||||||
impl StructTrait {
|
impl StructTrait {
|
||||||
fn serialize_field(&self, span: Span) -> Tokens {
|
fn serialize_field(&self, span: Span) -> Tokens {
|
||||||
match *self {
|
match *self {
|
||||||
|
StructTrait::SerializeMap => {
|
||||||
|
quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry)
|
||||||
|
}
|
||||||
StructTrait::SerializeStruct => {
|
StructTrait::SerializeStruct => {
|
||||||
quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field)
|
quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field)
|
||||||
}
|
}
|
||||||
@@ -1027,14 +1091,15 @@ impl StructTrait {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip_field(&self, span: Span) -> Tokens {
|
fn skip_field(&self, span: Span) -> Option<Tokens> {
|
||||||
match *self {
|
match *self {
|
||||||
StructTrait::SerializeStruct => {
|
StructTrait::SerializeMap => None,
|
||||||
|
StructTrait::SerializeStruct => Some({
|
||||||
quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)
|
quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)
|
||||||
}
|
}),
|
||||||
StructTrait::SerializeStructVariant => {
|
StructTrait::SerializeStructVariant => Some({
|
||||||
quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)
|
quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive_internals"
|
name = "serde_derive_internals"
|
||||||
version = "0.20.1" # remember to update html_root_url
|
version = "0.22.2" # remember to update html_root_url
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
description = "AST representation used by Serde derive macros. Unstable."
|
description = "AST representation used by Serde derive macros. Unstable."
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ pub enum Style {
|
|||||||
|
|
||||||
impl<'a> Container<'a> {
|
impl<'a> Container<'a> {
|
||||||
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput) -> Container<'a> {
|
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput) -> Container<'a> {
|
||||||
let attrs = attr::Container::from_ast(cx, item);
|
let mut attrs = attr::Container::from_ast(cx, item);
|
||||||
|
|
||||||
let mut data = match item.data {
|
let mut data = match item.data {
|
||||||
syn::Data::Enum(ref data) => {
|
syn::Data::Enum(ref data) => {
|
||||||
@@ -63,6 +63,7 @@ impl<'a> Container<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut has_flatten = false;
|
||||||
match data {
|
match data {
|
||||||
Data::Enum(ref mut variants) => for variant in variants {
|
Data::Enum(ref mut variants) => for variant in variants {
|
||||||
variant.attrs.rename_by_rule(attrs.rename_all());
|
variant.attrs.rename_by_rule(attrs.rename_all());
|
||||||
@@ -71,10 +72,17 @@ impl<'a> Container<'a> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Data::Struct(_, ref mut fields) => for field in fields {
|
Data::Struct(_, ref mut fields) => for field in fields {
|
||||||
|
if field.attrs.flatten() {
|
||||||
|
has_flatten = true;
|
||||||
|
}
|
||||||
field.attrs.rename_by_rule(attrs.rename_all());
|
field.attrs.rename_by_rule(attrs.rename_all());
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if has_flatten {
|
||||||
|
attrs.mark_has_flatten();
|
||||||
|
}
|
||||||
|
|
||||||
let item = Container {
|
let item = Container {
|
||||||
ident: item.ident,
|
ident: item.ident,
|
||||||
attrs: attrs,
|
attrs: attrs,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ use proc_macro2::{Span, TokenStream, TokenNode, TokenTree};
|
|||||||
|
|
||||||
pub use case::RenameRule;
|
pub use case::RenameRule;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
struct Attr<'c, T> {
|
struct Attr<'c, T> {
|
||||||
cx: &'c Ctxt,
|
cx: &'c Ctxt,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
@@ -114,6 +115,7 @@ pub struct Container {
|
|||||||
type_into: Option<syn::Type>,
|
type_into: Option<syn::Type>,
|
||||||
remote: Option<syn::Path>,
|
remote: Option<syn::Path>,
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
|
has_flatten: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Styles of representing an enum.
|
/// Styles of representing an enum.
|
||||||
@@ -243,7 +245,7 @@ impl Container {
|
|||||||
|
|
||||||
// Parse `#[serde(default = "...")]`
|
// Parse `#[serde(default = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "default" => {
|
Meta(NameValue(ref m)) if m.ident == "default" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
match item.data {
|
match item.data {
|
||||||
syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(_), .. }) => {
|
syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(_), .. }) => {
|
||||||
default.set(Default::Path(path));
|
default.set(Default::Path(path));
|
||||||
@@ -330,7 +332,11 @@ impl Container {
|
|||||||
// Parse `#[serde(remote = "...")]`
|
// Parse `#[serde(remote = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "remote" => {
|
Meta(NameValue(ref m)) if m.ident == "remote" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
remote.set(path);
|
if is_primitive_path(&path, "Self") {
|
||||||
|
remote.set(item.ident.into());
|
||||||
|
} else {
|
||||||
|
remote.set(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,6 +379,7 @@ impl Container {
|
|||||||
type_into: type_into.get(),
|
type_into: type_into.get(),
|
||||||
remote: remote.get(),
|
remote: remote.get(),
|
||||||
identifier: decide_identifier(cx, item, &field_identifier, &variant_identifier),
|
identifier: decide_identifier(cx, item, &field_identifier, &variant_identifier),
|
||||||
|
has_flatten: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,6 +426,14 @@ impl Container {
|
|||||||
pub fn identifier(&self) -> Identifier {
|
pub fn identifier(&self) -> Identifier {
|
||||||
self.identifier
|
self.identifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_flatten(&self) -> bool {
|
||||||
|
self.has_flatten
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mark_has_flatten(&mut self) {
|
||||||
|
self.has_flatten = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decide_tag(
|
fn decide_tag(
|
||||||
@@ -510,8 +525,8 @@ pub struct Variant {
|
|||||||
skip_deserializing: bool,
|
skip_deserializing: bool,
|
||||||
skip_serializing: bool,
|
skip_serializing: bool,
|
||||||
other: bool,
|
other: bool,
|
||||||
serialize_with: Option<syn::Path>,
|
serialize_with: Option<syn::ExprPath>,
|
||||||
deserialize_with: Option<syn::Path>,
|
deserialize_with: Option<syn::ExprPath>,
|
||||||
borrow: Option<syn::Meta>,
|
borrow: Option<syn::Meta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,26 +592,26 @@ impl Variant {
|
|||||||
|
|
||||||
// Parse `#[serde(with = "...")]`
|
// Parse `#[serde(with = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "with" => {
|
Meta(NameValue(ref m)) if m.ident == "with" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
let mut ser_path = path.clone();
|
let mut ser_path = path.clone();
|
||||||
ser_path.segments.push(Ident::new("serialize", Span::call_site()).into());
|
ser_path.path.segments.push(Ident::new("serialize", Span::call_site()).into());
|
||||||
serialize_with.set(ser_path);
|
serialize_with.set(ser_path);
|
||||||
let mut de_path = path;
|
let mut de_path = path;
|
||||||
de_path.segments.push(Ident::new("deserialize", Span::call_site()).into());
|
de_path.path.segments.push(Ident::new("deserialize", Span::call_site()).into());
|
||||||
deserialize_with.set(de_path);
|
deserialize_with.set(de_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(serialize_with = "...")]`
|
// Parse `#[serde(serialize_with = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
|
Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
serialize_with.set(path);
|
serialize_with.set(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(deserialize_with = "...")]`
|
// Parse `#[serde(deserialize_with = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
|
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
deserialize_with.set(path);
|
deserialize_with.set(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -675,11 +690,11 @@ impl Variant {
|
|||||||
self.other
|
self.other
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_with(&self) -> Option<&syn::Path> {
|
pub fn serialize_with(&self) -> Option<&syn::ExprPath> {
|
||||||
self.serialize_with.as_ref()
|
self.serialize_with.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize_with(&self) -> Option<&syn::Path> {
|
pub fn deserialize_with(&self) -> Option<&syn::ExprPath> {
|
||||||
self.deserialize_with.as_ref()
|
self.deserialize_with.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -691,14 +706,15 @@ pub struct Field {
|
|||||||
de_renamed: bool,
|
de_renamed: bool,
|
||||||
skip_serializing: bool,
|
skip_serializing: bool,
|
||||||
skip_deserializing: bool,
|
skip_deserializing: bool,
|
||||||
skip_serializing_if: Option<syn::Path>,
|
skip_serializing_if: Option<syn::ExprPath>,
|
||||||
default: Default,
|
default: Default,
|
||||||
serialize_with: Option<syn::Path>,
|
serialize_with: Option<syn::ExprPath>,
|
||||||
deserialize_with: Option<syn::Path>,
|
deserialize_with: Option<syn::ExprPath>,
|
||||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
borrowed_lifetimes: BTreeSet<syn::Lifetime>,
|
borrowed_lifetimes: BTreeSet<syn::Lifetime>,
|
||||||
getter: Option<syn::Path>,
|
getter: Option<syn::ExprPath>,
|
||||||
|
flatten: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the default to use for a field when deserializing.
|
/// Represents the default to use for a field when deserializing.
|
||||||
@@ -708,7 +724,7 @@ pub enum Default {
|
|||||||
/// The default is given by `std::default::Default::default()`.
|
/// The default is given by `std::default::Default::default()`.
|
||||||
Default,
|
Default,
|
||||||
/// The default is given by this function.
|
/// The default is given by this function.
|
||||||
Path(syn::Path),
|
Path(syn::ExprPath),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Field {
|
impl Field {
|
||||||
@@ -732,6 +748,7 @@ impl Field {
|
|||||||
let mut de_bound = Attr::none(cx, "bound");
|
let mut de_bound = Attr::none(cx, "bound");
|
||||||
let mut borrowed_lifetimes = Attr::none(cx, "borrow");
|
let mut borrowed_lifetimes = Attr::none(cx, "borrow");
|
||||||
let mut getter = Attr::none(cx, "getter");
|
let mut getter = Attr::none(cx, "getter");
|
||||||
|
let mut flatten = BoolAttr::none(cx, "flatten");
|
||||||
|
|
||||||
let ident = match field.ident {
|
let ident = match field.ident {
|
||||||
Some(ref ident) => ident.to_string(),
|
Some(ref ident) => ident.to_string(),
|
||||||
@@ -775,7 +792,7 @@ impl Field {
|
|||||||
|
|
||||||
// Parse `#[serde(default = "...")]`
|
// Parse `#[serde(default = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "default" => {
|
Meta(NameValue(ref m)) if m.ident == "default" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
default.set(Default::Path(path));
|
default.set(Default::Path(path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -798,33 +815,33 @@ impl Field {
|
|||||||
|
|
||||||
// Parse `#[serde(skip_serializing_if = "...")]`
|
// Parse `#[serde(skip_serializing_if = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => {
|
Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
skip_serializing_if.set(path);
|
skip_serializing_if.set(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(serialize_with = "...")]`
|
// Parse `#[serde(serialize_with = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
|
Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
serialize_with.set(path);
|
serialize_with.set(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(deserialize_with = "...")]`
|
// Parse `#[serde(deserialize_with = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
|
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
deserialize_with.set(path);
|
deserialize_with.set(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(with = "...")]`
|
// Parse `#[serde(with = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "with" => {
|
Meta(NameValue(ref m)) if m.ident == "with" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
let mut ser_path = path.clone();
|
let mut ser_path = path.clone();
|
||||||
ser_path.segments.push(Ident::new("serialize", Span::call_site()).into());
|
ser_path.path.segments.push(Ident::new("serialize", Span::call_site()).into());
|
||||||
serialize_with.set(ser_path);
|
serialize_with.set(ser_path);
|
||||||
let mut de_path = path;
|
let mut de_path = path;
|
||||||
de_path.segments.push(Ident::new("deserialize", Span::call_site()).into());
|
de_path.path.segments.push(Ident::new("deserialize", Span::call_site()).into());
|
||||||
deserialize_with.set(de_path);
|
deserialize_with.set(de_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -873,11 +890,16 @@ impl Field {
|
|||||||
|
|
||||||
// Parse `#[serde(getter = "...")]`
|
// Parse `#[serde(getter = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "getter" => {
|
Meta(NameValue(ref m)) if m.ident == "getter" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
|
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
|
||||||
getter.set(path);
|
getter.set(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(flatten)]`
|
||||||
|
Meta(Word(word)) if word == "flatten" => {
|
||||||
|
flatten.set_true();
|
||||||
|
}
|
||||||
|
|
||||||
Meta(ref meta_item) => {
|
Meta(ref meta_item) => {
|
||||||
cx.error(format!(
|
cx.error(format!(
|
||||||
"unknown serde field attribute `{}`",
|
"unknown serde field attribute `{}`",
|
||||||
@@ -921,7 +943,12 @@ impl Field {
|
|||||||
path.segments.push(Ident::new("private", Span::def_site()).into());
|
path.segments.push(Ident::new("private", Span::def_site()).into());
|
||||||
path.segments.push(Ident::new("de", Span::def_site()).into());
|
path.segments.push(Ident::new("de", Span::def_site()).into());
|
||||||
path.segments.push(Ident::new("borrow_cow_str", Span::def_site()).into());
|
path.segments.push(Ident::new("borrow_cow_str", Span::def_site()).into());
|
||||||
deserialize_with.set_if_none(path);
|
let expr = syn::ExprPath {
|
||||||
|
attrs: Vec::new(),
|
||||||
|
qself: None,
|
||||||
|
path: path,
|
||||||
|
};
|
||||||
|
deserialize_with.set_if_none(expr);
|
||||||
} else if is_cow(&field.ty, is_slice_u8) {
|
} else if is_cow(&field.ty, is_slice_u8) {
|
||||||
let mut path = syn::Path {
|
let mut path = syn::Path {
|
||||||
leading_colon: None,
|
leading_colon: None,
|
||||||
@@ -931,7 +958,12 @@ impl Field {
|
|||||||
path.segments.push(Ident::new("private", Span::def_site()).into());
|
path.segments.push(Ident::new("private", Span::def_site()).into());
|
||||||
path.segments.push(Ident::new("de", Span::def_site()).into());
|
path.segments.push(Ident::new("de", Span::def_site()).into());
|
||||||
path.segments.push(Ident::new("borrow_cow_bytes", Span::def_site()).into());
|
path.segments.push(Ident::new("borrow_cow_bytes", Span::def_site()).into());
|
||||||
deserialize_with.set_if_none(path);
|
let expr = syn::ExprPath {
|
||||||
|
attrs: Vec::new(),
|
||||||
|
qself: None,
|
||||||
|
path: path,
|
||||||
|
};
|
||||||
|
deserialize_with.set_if_none(expr);
|
||||||
}
|
}
|
||||||
} else if is_rptr(&field.ty, is_str) || is_rptr(&field.ty, is_slice_u8) {
|
} else if is_rptr(&field.ty, is_str) || is_rptr(&field.ty, is_slice_u8) {
|
||||||
// Types &str and &[u8] are always implicitly borrowed. No need for
|
// Types &str and &[u8] are always implicitly borrowed. No need for
|
||||||
@@ -960,6 +992,7 @@ impl Field {
|
|||||||
de_bound: de_bound.get(),
|
de_bound: de_bound.get(),
|
||||||
borrowed_lifetimes: borrowed_lifetimes,
|
borrowed_lifetimes: borrowed_lifetimes,
|
||||||
getter: getter.get(),
|
getter: getter.get(),
|
||||||
|
flatten: flatten.get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -984,7 +1017,7 @@ impl Field {
|
|||||||
self.skip_deserializing
|
self.skip_deserializing
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip_serializing_if(&self) -> Option<&syn::Path> {
|
pub fn skip_serializing_if(&self) -> Option<&syn::ExprPath> {
|
||||||
self.skip_serializing_if.as_ref()
|
self.skip_serializing_if.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -992,11 +1025,11 @@ impl Field {
|
|||||||
&self.default
|
&self.default
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_with(&self) -> Option<&syn::Path> {
|
pub fn serialize_with(&self) -> Option<&syn::ExprPath> {
|
||||||
self.serialize_with.as_ref()
|
self.serialize_with.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize_with(&self) -> Option<&syn::Path> {
|
pub fn deserialize_with(&self) -> Option<&syn::ExprPath> {
|
||||||
self.deserialize_with.as_ref()
|
self.deserialize_with.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1012,9 +1045,13 @@ impl Field {
|
|||||||
&self.borrowed_lifetimes
|
&self.borrowed_lifetimes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getter(&self) -> Option<&syn::Path> {
|
pub fn getter(&self) -> Option<&syn::ExprPath> {
|
||||||
self.getter.as_ref()
|
self.getter.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flatten(&self) -> bool {
|
||||||
|
self.flatten
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SerAndDe<T> = (Option<T>, Option<T>);
|
type SerAndDe<T> = (Option<T>, Option<T>);
|
||||||
@@ -1107,6 +1144,11 @@ fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn
|
|||||||
parse_lit_str(string).map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value())))
|
parse_lit_str(string).map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_lit_into_expr_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::ExprPath, ()> {
|
||||||
|
let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
|
||||||
|
parse_lit_str(string).map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value())))
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_lit_into_where(
|
fn parse_lit_into_where(
|
||||||
cx: &Ctxt,
|
cx: &Ctxt,
|
||||||
attr_name: &str,
|
attr_name: &str,
|
||||||
@@ -1253,29 +1295,32 @@ fn is_rptr(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_str(ty: &syn::Type) -> bool {
|
fn is_str(ty: &syn::Type) -> bool {
|
||||||
is_primitive_path(ty, "str")
|
is_primitive_type(ty, "str")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_slice_u8(ty: &syn::Type) -> bool {
|
fn is_slice_u8(ty: &syn::Type) -> bool {
|
||||||
match *ty {
|
match *ty {
|
||||||
syn::Type::Slice(ref ty) => is_primitive_path(&ty.elem, "u8"),
|
syn::Type::Slice(ref ty) => is_primitive_type(&ty.elem, "u8"),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_primitive_path(ty: &syn::Type, primitive: &str) -> bool {
|
fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool {
|
||||||
match *ty {
|
match *ty {
|
||||||
syn::Type::Path(ref ty) => {
|
syn::Type::Path(ref ty) => {
|
||||||
ty.qself.is_none()
|
ty.qself.is_none() && is_primitive_path(&ty.path, primitive)
|
||||||
&& ty.path.leading_colon.is_none()
|
|
||||||
&& ty.path.segments.len() == 1
|
|
||||||
&& ty.path.segments[0].ident == primitive
|
|
||||||
&& ty.path.segments[0].arguments.is_empty()
|
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool {
|
||||||
|
path.leading_colon.is_none()
|
||||||
|
&& path.segments.len() == 1
|
||||||
|
&& path.segments[0].ident == primitive
|
||||||
|
&& path.segments[0].arguments.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
// All lifetimes that this type could borrow from a Deserializer.
|
// All lifetimes that this type could borrow from a Deserializer.
|
||||||
//
|
//
|
||||||
// For example a type `S<'a, 'b>` could borrow `'a` and `'b`. On the other hand
|
// For example a type `S<'a, 'b>` could borrow `'a` and `'b`. On the other hand
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726
|
// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726
|
||||||
#[allow(unused_imports)]
|
#[allow(deprecated, unused_imports)]
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use Ctxt;
|
|||||||
/// object. Simpler checks should happen when parsing and building the attrs.
|
/// object. Simpler checks should happen when parsing and building the attrs.
|
||||||
pub fn check(cx: &Ctxt, cont: &Container) {
|
pub fn check(cx: &Ctxt, cont: &Container) {
|
||||||
check_getter(cx, cont);
|
check_getter(cx, cont);
|
||||||
|
check_flatten(cx, cont);
|
||||||
check_identifier(cx, cont);
|
check_identifier(cx, cont);
|
||||||
check_variant_skip_attrs(cx, cont);
|
check_variant_skip_attrs(cx, cont);
|
||||||
check_internal_tag_field_name_conflict(cx, cont);
|
check_internal_tag_field_name_conflict(cx, cont);
|
||||||
@@ -40,6 +41,38 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Flattening has some restrictions we can test.
|
||||||
|
fn check_flatten(cx: &Ctxt, cont: &Container) {
|
||||||
|
match cont.data {
|
||||||
|
Data::Enum(_) => {
|
||||||
|
assert!(!cont.attrs.has_flatten());
|
||||||
|
}
|
||||||
|
Data::Struct(_, _) => {
|
||||||
|
for field in cont.data.all_fields() {
|
||||||
|
if !field.attrs.flatten() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if field.attrs.skip_serializing() {
|
||||||
|
cx.error(
|
||||||
|
"#[serde(flatten] can not be combined with \
|
||||||
|
#[serde(skip_serializing)]"
|
||||||
|
);
|
||||||
|
} else if field.attrs.skip_serializing_if().is_some() {
|
||||||
|
cx.error(
|
||||||
|
"#[serde(flatten] can not be combined with \
|
||||||
|
#[serde(skip_serializing_if = \"...\")]"
|
||||||
|
);
|
||||||
|
} else if field.attrs.skip_deserializing() {
|
||||||
|
cx.error(
|
||||||
|
"#[serde(flatten] can not be combined with \
|
||||||
|
#[serde(skip_deserializing)]"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The `other` attribute must be used at most once and it must be the last
|
/// The `other` attribute must be used at most once and it must be the last
|
||||||
/// variant of an enum that has the `field_identifier` attribute.
|
/// variant of an enum that has the `field_identifier` attribute.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.20.1")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.22.2")]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity, doc_markdown, match_same_arms,
|
#![cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity, doc_markdown, match_same_arms,
|
||||||
redundant_field_names))]
|
redundant_field_names))]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_test"
|
name = "serde_test"
|
||||||
version = "1.0.32" # remember to update html_root_url
|
version = "1.0.36" # remember to update html_root_url
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
description = "Token De/Serializer for testing De/Serialize implementations"
|
description = "Token De/Serializer for testing De/Serialize implementations"
|
||||||
|
|||||||
@@ -155,7 +155,7 @@
|
|||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.32")]
|
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.36")]
|
||||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||||
// Whitelisted clippy lints
|
// Whitelisted clippy lints
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
|
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2018 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: #[serde(flatten] can not be combined with #[serde(skip_deserializing)]
|
||||||
|
struct Foo {
|
||||||
|
#[serde(flatten, skip_deserializing)]
|
||||||
|
other: Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Other {
|
||||||
|
x: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2018 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: #[serde(flatten] can not be combined with #[serde(skip_serializing_if = "...")]
|
||||||
|
struct Foo {
|
||||||
|
#[serde(flatten, skip_serializing_if="Option::is_none")]
|
||||||
|
other: Option<Other>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Other {
|
||||||
|
x: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2018 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: #[serde(flatten] can not be combined with #[serde(skip_serializing)]
|
||||||
|
struct Foo {
|
||||||
|
#[serde(flatten, skip_serializing)]
|
||||||
|
other: Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Other {
|
||||||
|
x: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -12,12 +12,13 @@
|
|||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
use std::collections::HashMap;
|
||||||
use self::serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use self::serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use self::serde::de::{self, Unexpected};
|
use self::serde::de::{self, Unexpected};
|
||||||
|
|
||||||
extern crate serde_test;
|
extern crate serde_test;
|
||||||
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens,
|
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens,
|
||||||
Token};
|
assert_ser_tokens_error, assert_tokens, Token};
|
||||||
|
|
||||||
trait MyDefault: Sized {
|
trait MyDefault: Sized {
|
||||||
fn my_default() -> Self;
|
fn my_default() -> Self;
|
||||||
@@ -94,6 +95,56 @@ where
|
|||||||
a5: E,
|
a5: E,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct CollectOther {
|
||||||
|
a: u32,
|
||||||
|
b: u32,
|
||||||
|
#[serde(flatten)]
|
||||||
|
extra: HashMap<String, u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct FlattenStructEnumWrapper {
|
||||||
|
#[serde(flatten)]
|
||||||
|
data: FlattenStructEnum,
|
||||||
|
#[serde(flatten)]
|
||||||
|
extra: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
enum FlattenStructEnum {
|
||||||
|
InsertInteger {
|
||||||
|
index: u32,
|
||||||
|
value: u32
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct FlattenStructTagContentEnumWrapper {
|
||||||
|
outer: u32,
|
||||||
|
#[serde(flatten)]
|
||||||
|
data: FlattenStructTagContentEnumNewtype,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct FlattenStructTagContentEnumNewtype(pub FlattenStructTagContentEnum);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "snake_case", tag = "type", content = "value")]
|
||||||
|
enum FlattenStructTagContentEnum {
|
||||||
|
InsertInteger {
|
||||||
|
index: u32,
|
||||||
|
value: u32
|
||||||
|
},
|
||||||
|
NewtypeVariant(FlattenStructTagContentEnumNewtypeVariant),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct FlattenStructTagContentEnumNewtypeVariant {
|
||||||
|
value: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default_struct() {
|
fn test_default_struct() {
|
||||||
assert_de_tokens(
|
assert_de_tokens(
|
||||||
@@ -1267,3 +1318,482 @@ fn test_from_into_traits() {
|
|||||||
assert_ser_tokens::<StructFromEnum>(&StructFromEnum(None), &[Token::None]);
|
assert_ser_tokens::<StructFromEnum>(&StructFromEnum(None), &[Token::None]);
|
||||||
assert_de_tokens::<StructFromEnum>(&StructFromEnum(Some(2)), &[Token::Some, Token::U32(2)]);
|
assert_de_tokens::<StructFromEnum>(&StructFromEnum(Some(2)), &[Token::Some, Token::U32(2)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_collect_other() {
|
||||||
|
let mut extra = HashMap::new();
|
||||||
|
extra.insert("c".into(), 3);
|
||||||
|
assert_tokens(
|
||||||
|
&CollectOther { a: 1, b: 2, extra },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::U32(1),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::U32(2),
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::U32(3),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_flatten_struct_enum() {
|
||||||
|
let mut extra = HashMap::new();
|
||||||
|
extra.insert("extra_key".into(), "extra value".into());
|
||||||
|
let change_request = FlattenStructEnumWrapper {
|
||||||
|
data: FlattenStructEnum::InsertInteger {
|
||||||
|
index: 0,
|
||||||
|
value: 42
|
||||||
|
},
|
||||||
|
extra,
|
||||||
|
};
|
||||||
|
assert_de_tokens(
|
||||||
|
&change_request,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("insert_integer"),
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("index"),
|
||||||
|
Token::U32(0),
|
||||||
|
Token::Str("value"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::MapEnd,
|
||||||
|
Token::Str("extra_key"),
|
||||||
|
Token::Str("extra value"),
|
||||||
|
Token::MapEnd
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_ser_tokens(
|
||||||
|
&change_request,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("insert_integer"),
|
||||||
|
Token::Struct { len: 2, name: "insert_integer" },
|
||||||
|
Token::Str("index"),
|
||||||
|
Token::U32(0),
|
||||||
|
Token::Str("value"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::StructEnd,
|
||||||
|
Token::Str("extra_key"),
|
||||||
|
Token::Str("extra value"),
|
||||||
|
Token::MapEnd
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_flatten_struct_tag_content_enum() {
|
||||||
|
let change_request = FlattenStructTagContentEnumWrapper {
|
||||||
|
outer: 42,
|
||||||
|
data: FlattenStructTagContentEnumNewtype(
|
||||||
|
FlattenStructTagContentEnum::InsertInteger {
|
||||||
|
index: 0,
|
||||||
|
value: 42
|
||||||
|
}
|
||||||
|
),
|
||||||
|
};
|
||||||
|
assert_de_tokens(
|
||||||
|
&change_request,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("outer"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::Str("type"),
|
||||||
|
Token::Str("insert_integer"),
|
||||||
|
Token::Str("value"),
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("index"),
|
||||||
|
Token::U32(0),
|
||||||
|
Token::Str("value"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::MapEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_ser_tokens(
|
||||||
|
&change_request,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("outer"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::Str("type"),
|
||||||
|
Token::Str("insert_integer"),
|
||||||
|
Token::Str("value"),
|
||||||
|
Token::Struct { len: 2, name: "insert_integer" },
|
||||||
|
Token::Str("index"),
|
||||||
|
Token::U32(0),
|
||||||
|
Token::Str("value"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::StructEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_flatten_struct_tag_content_enum_newtype() {
|
||||||
|
let change_request = FlattenStructTagContentEnumWrapper {
|
||||||
|
outer: 42,
|
||||||
|
data: FlattenStructTagContentEnumNewtype(
|
||||||
|
FlattenStructTagContentEnum::NewtypeVariant(
|
||||||
|
FlattenStructTagContentEnumNewtypeVariant {
|
||||||
|
value: 23
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
assert_de_tokens(
|
||||||
|
&change_request,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("outer"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::Str("type"),
|
||||||
|
Token::Str("newtype_variant"),
|
||||||
|
Token::Str("value"),
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("value"),
|
||||||
|
Token::U32(23),
|
||||||
|
Token::MapEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_ser_tokens(
|
||||||
|
&change_request,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("outer"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::Str("type"),
|
||||||
|
Token::Str("newtype_variant"),
|
||||||
|
Token::Str("value"),
|
||||||
|
Token::Struct { len: 1, name: "FlattenStructTagContentEnumNewtypeVariant" },
|
||||||
|
Token::Str("value"),
|
||||||
|
Token::U32(23),
|
||||||
|
Token::StructEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unknown_field_in_flatten() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
struct Outer {
|
||||||
|
dummy: String,
|
||||||
|
#[serde(flatten)]
|
||||||
|
inner: Inner,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct Inner {
|
||||||
|
foo: HashMap<String, u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens_error::<Outer>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Outer",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("dummy"),
|
||||||
|
Token::Str("23"),
|
||||||
|
Token::Str("foo"),
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::U32(1),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::U32(2),
|
||||||
|
Token::MapEnd,
|
||||||
|
Token::Str("bar"),
|
||||||
|
Token::U32(23),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
"unknown field `bar`",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_complex_flatten() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct Outer {
|
||||||
|
y: u32,
|
||||||
|
#[serde(flatten)]
|
||||||
|
first: First,
|
||||||
|
#[serde(flatten)]
|
||||||
|
second: Second,
|
||||||
|
z: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct First {
|
||||||
|
a: u32,
|
||||||
|
b: bool,
|
||||||
|
c: Vec<String>,
|
||||||
|
d: String,
|
||||||
|
e: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct Second {
|
||||||
|
f: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Outer {
|
||||||
|
y: 0,
|
||||||
|
first: First {
|
||||||
|
a: 1,
|
||||||
|
b: true,
|
||||||
|
c: vec!["a".into(), "b".into()],
|
||||||
|
d: "c".into(),
|
||||||
|
e: Some(2),
|
||||||
|
},
|
||||||
|
second: Second {
|
||||||
|
f: 3
|
||||||
|
},
|
||||||
|
z: 4
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("y"),
|
||||||
|
Token::U32(0),
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::U32(1),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::Bool(true),
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Seq { len: Some(2) },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::SeqEnd,
|
||||||
|
Token::Str("d"),
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Str("e"),
|
||||||
|
Token::U64(2),
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::U32(3),
|
||||||
|
Token::Str("z"),
|
||||||
|
Token::U32(4),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_ser_tokens(
|
||||||
|
&Outer {
|
||||||
|
y: 0,
|
||||||
|
first: First {
|
||||||
|
a: 1,
|
||||||
|
b: true,
|
||||||
|
c: vec!["a".into(), "b".into()],
|
||||||
|
d: "c".into(),
|
||||||
|
e: Some(2),
|
||||||
|
},
|
||||||
|
second: Second {
|
||||||
|
f: 3
|
||||||
|
},
|
||||||
|
z: 4
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("y"),
|
||||||
|
Token::U32(0),
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::U32(1),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::Bool(true),
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Seq { len: Some(2) },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::SeqEnd,
|
||||||
|
Token::Str("d"),
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Str("e"),
|
||||||
|
Token::Some,
|
||||||
|
Token::U64(2),
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::U32(3),
|
||||||
|
Token::Str("z"),
|
||||||
|
Token::U32(4),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_flatten_unsupported_type() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct Outer {
|
||||||
|
outer: String,
|
||||||
|
#[serde(flatten)]
|
||||||
|
inner: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_ser_tokens_error(
|
||||||
|
&Outer {
|
||||||
|
outer: "foo".into(),
|
||||||
|
inner: "bar".into(),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("outer"),
|
||||||
|
Token::Str("foo"),
|
||||||
|
],
|
||||||
|
"can only flatten structs and maps (got a string)",
|
||||||
|
);
|
||||||
|
assert_de_tokens_error::<Outer>(
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("outer"),
|
||||||
|
Token::Str("foo"),
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::MapEnd
|
||||||
|
],
|
||||||
|
"can only flatten structs and maps",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_non_string_keys() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct TestStruct {
|
||||||
|
name: String,
|
||||||
|
age: u32,
|
||||||
|
#[serde(flatten)]
|
||||||
|
mapping: HashMap<u32, u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut mapping = HashMap::new();
|
||||||
|
mapping.insert(0, 42);
|
||||||
|
assert_tokens(
|
||||||
|
&TestStruct { name: "peter".into(), age: 3, mapping },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("name"),
|
||||||
|
Token::Str("peter"),
|
||||||
|
Token::Str("age"),
|
||||||
|
Token::U32(3),
|
||||||
|
Token::U32(0),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lifetime_propagation_for_flatten() {
|
||||||
|
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
||||||
|
struct A<T> {
|
||||||
|
#[serde(flatten)]
|
||||||
|
t: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
||||||
|
struct B<'a> {
|
||||||
|
#[serde(flatten, borrow)]
|
||||||
|
t: HashMap<&'a str, u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
||||||
|
struct C<'a> {
|
||||||
|
#[serde(flatten, borrow)]
|
||||||
|
t: HashMap<&'a [u8], u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut owned_map = HashMap::new();
|
||||||
|
owned_map.insert("x".to_string(), 42u32);
|
||||||
|
assert_tokens(
|
||||||
|
&A { t: owned_map },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("x"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut borrowed_map = HashMap::new();
|
||||||
|
borrowed_map.insert("x", 42u32);
|
||||||
|
assert_ser_tokens(
|
||||||
|
&B { t: borrowed_map.clone() },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::BorrowedStr("x"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&B { t: borrowed_map },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::BorrowedStr("x"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut borrowed_map = HashMap::new();
|
||||||
|
borrowed_map.insert(&b"x"[..], 42u32);
|
||||||
|
assert_ser_tokens(
|
||||||
|
&C { t: borrowed_map.clone() },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Seq { len: Some(1) },
|
||||||
|
Token::U8(120),
|
||||||
|
Token::SeqEnd,
|
||||||
|
Token::U32(42),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&C { t: borrowed_map },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::BorrowedBytes(b"x"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_flatten_enum_newtype() {
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct S {
|
||||||
|
#[serde(flatten)]
|
||||||
|
flat: E,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
enum E {
|
||||||
|
Q(HashMap<String, String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
let e = E::Q({
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
map.insert("k".to_owned(), "v".to_owned());
|
||||||
|
map
|
||||||
|
});
|
||||||
|
let s = S { flat: e };
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&s,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("Q"),
|
||||||
|
Token::Map { len: Some(1) },
|
||||||
|
Token::Str("k"),
|
||||||
|
Token::Str("v"),
|
||||||
|
Token::MapEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -385,6 +385,10 @@ fn test_gen() {
|
|||||||
s: vis::S,
|
s: vis::S,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(remote = "Self")]
|
||||||
|
struct RemoteSelf;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
enum ExternallyTaggedVariantWith {
|
enum ExternallyTaggedVariantWith {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -528,6 +532,13 @@ fn test_gen() {
|
|||||||
marker: PhantomData<T>,
|
marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
assert::<TypeMacro<X>>();
|
assert::<TypeMacro<X>>();
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct BigArray {
|
||||||
|
#[serde(serialize_with = "<[_]>::serialize")]
|
||||||
|
array: [u8; 256],
|
||||||
|
}
|
||||||
|
assert_ser::<BigArray>();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
Reference in New Issue
Block a user