Compare commits

...

72 Commits

Author SHA1 Message Date
David Tolnay 7c04c98e0e Release 1.0.36 2018-03-27 11:35:45 +02:00
David Tolnay a2fa4c2570 Merge pull request #1196 from serde-rs/self
Special case remote = "Self"
2018-03-27 11:12:04 +02:00
David Tolnay 42430902e2 Special case remote = "Self" 2018-03-27 10:56:05 +02:00
David Tolnay 23e2e92237 Release 1.0.35 2018-03-25 12:59:02 +02:00
David Tolnay 273b2c11c6 Keep using deprecated AsciiExt on old compilers 2018-03-25 12:45:31 +02:00
David Tolnay c1602a4d76 Deserialize map in place cannot have flatten attributes 2018-03-25 12:42:36 +02:00
David Tolnay c23be3f855 Revert flatten change in deserialize in place 2018-03-25 12:39:20 +02:00
David Tolnay 5c9c97c0ce Remove test that fails to parse flatten attribute 2018-03-25 12:33:50 +02:00
David Tolnay e5ed440136 Always check flatten assertions 2018-03-25 12:32:06 +02:00
David Tolnay d45ca2f5e4 Re-export NonZero* types from ::lib 2018-03-25 12:30:35 +02:00
David Tolnay d7f9f8209d Indicate that NonZero<T> is deprecated 2018-03-25 12:26:06 +02:00
David Tolnay 4a2612ecff Merge pull request #1191 from SimonSapin/nonzero
impl Serialize and Deserialize for std::num::NonZero*
2018-03-25 03:24:51 -07:00
Simon Sapin 05b22a06d7 impl Serialize and Deserialize for std::num::NonZero*
… gated on the `unstable` Cargo feature.

These are new standard library types.
2018-03-25 12:23:55 +02:00
David Tolnay 3145bcc46e Merge pull request 1159 from niklasad1/patch-1 2018-03-24 19:42:14 +01:00
David Tolnay 2b18b57d84 Release 1.0.34 2018-03-22 15:06:21 -07:00
David Tolnay 5520202262 Merge pull request #1179 from mitsuhiko/feature/flatten
Support for Flattening
2018-03-22 14:14:23 -07:00
Armin Ronacher 3d647f4063 Fixed a compilefail test for flatten on enums 2018-03-20 23:26:22 +01:00
Armin Ronacher 0fde3c2ee8 Fix a warning caused by no-default-features 2018-03-20 23:06:55 +01:00
Armin Ronacher 27f935f036 Correctly serialize newtype variants for flatten 2018-03-20 23:05:05 +01:00
Armin Ronacher 99614c7266 Added flatten on enum compile fail test 2018-03-20 22:15:47 +01:00
Armin Ronacher bb2ecb3bc4 Added compilefail tests for flatten conflicts 2018-03-20 22:04:12 +01:00
Armin Ronacher 96393bfcc7 Added checks for flatten attribute 2018-03-20 21:48:25 +01:00
Armin Ronacher 1d92569abc Added explanatory comment about fetching data from buffered content 2018-03-20 21:24:00 +01:00
Armin Ronacher e4ef087735 Added support for borrowing when flattening 2018-03-20 15:19:36 +01:00
Armin Ronacher 695c3eedcb Do not imply flatten from skip_serialize 2018-03-20 14:45:14 +01:00
Armin Ronacher 50c636a923 Remove now dead as_map detection (can be cattrs.has_flatten) 2018-03-20 13:43:23 +01:00
Armin Ronacher 5b884b5bf9 Added some missing UFCs 2018-03-20 13:38:22 +01:00
Armin Ronacher 8637dda60f Refactored a test 2018-03-20 13:38:08 +01:00
Armin Ronacher abeea89147 Fully qualify some calls in generated code and fix a bad comment 2018-03-20 13:35:16 +01:00
Armin Ronacher 6e324e887d Some refactoring to use a bit less unwrap() 2018-03-20 13:20:56 +01:00
Armin Ronacher 7c596c7136 Remove unnecessary as_str 2018-03-20 13:11:17 +01:00
Armin Ronacher f02dbf381b Added non string key support for flattening 2018-03-19 00:57:58 +01:00
Armin Ronacher 7cf184624a Use more consistent error messages for bad flattening 2018-03-18 23:46:28 +01:00
Armin Ronacher c5a3128492 Added a more complex flattening test 2018-03-18 23:01:13 +01:00
Armin Ronacher 205f606962 Various clippy fixes 2018-03-18 22:59:27 +01:00
Armin Ronacher ad40f976db Switch to using Content keys internally for flattening to later support arbitrary keys 2018-03-18 21:07:08 +01:00
Armin Ronacher 58d52e784b Remove #[serde(repr = "map")] 2018-03-18 18:30:46 +01:00
Armin Ronacher d44f12907b Do not emit an in-place deserialization path for struct as map 2018-03-18 18:27:35 +01:00
Armin Ronacher 61b167be9a Attempted support for in_place deserialization for structs as map 2018-03-18 18:22:06 +01:00
Armin Ronacher f1af2dc5ab Added support for newtype variant serialization 2018-03-18 13:10:54 +01:00
Armin Ronacher ebc61baab2 Added newtype struct support for flattening 2018-03-18 13:02:00 +01:00
Armin Ronacher ffcde25b6e Fixed some clippy warnings 2018-03-17 00:49:00 +01:00
Armin Ronacher 2f57cecf13 format! -> format_args! for an error message 2018-03-16 23:38:50 +01:00
Armin Ronacher bfdcbae9db Fixed an unused import error 2018-03-16 23:30:55 +01:00
Armin Ronacher ca41e16e92 Added some missing conditionals for feature compilation 2018-03-16 23:20:14 +01:00
Armin Ronacher 352fe7b451 Removed an unused field that was left over from a merge conflict 2018-03-16 23:07:31 +01:00
Armin Ronacher 49e302d17d Improved error message for flattening on unsupported types 2018-03-16 23:05:48 +01:00
Armin Ronacher b8602a7e43 Added test for tag/content enum flattening 2018-03-16 23:05:48 +01:00
Armin Ronacher a8c8c2028e Added support for struct variant enum serialization 2018-03-16 23:05:48 +01:00
Armin Ronacher d1833c5602 Added support for basic enums in flatten 2018-03-16 23:05:48 +01:00
Armin Ronacher b4ef7ac323 Updated tests for flatten 2018-03-16 23:05:48 +01:00
Armin Ronacher ebf80ac965 Implement deserialization support for flatten 2018-03-16 23:05:48 +01:00
Armin Ronacher 112dfd7428 Correctly suppress the end() call for flattened serialization 2018-03-16 23:05:48 +01:00
Armin Ronacher b692923321 Non working changes to the flatten serializer 2018-03-16 23:05:48 +01:00
Armin Ronacher 9e8cda4c37 Added basic not fully working FlatMapSerializer 2018-03-16 23:05:48 +01:00
Jan Michael Auer 5457394f5b Fixed various issues with combinding flatten and deny_unknown_fields 2018-03-16 23:05:48 +01:00
Jan Michael Auer 6627540dd6 Added support basic deserialization in derive 2018-03-16 23:05:48 +01:00
Jan Michael Auer 5ae06bba49 Store flatten flag in container attributes 2018-03-16 23:05:47 +01:00
Jan Michael Auer 571bb8caed Derive serialization for serde(flatten) 2018-03-16 23:05:47 +01:00
Jan Michael Auer 299cd2dbd0 Replace unknown_fields_into with serde(flatten) 2018-03-16 23:05:47 +01:00
Armin Ronacher 583c0d8d14 Make proc-macro2/nightly happy 2018-03-16 23:05:22 +01:00
Armin Ronacher 07d07347b3 Make clippy happy 2018-03-16 23:05:22 +01:00
Armin Ronacher 77b07f3fbf Added tests for unknown_fields_into 2018-03-16 23:05:22 +01:00
Armin Ronacher 1bd2c6129c Explicitly pass value requirements for the capture path 2018-03-16 23:05:22 +01:00
Armin Ronacher 39413c8ce7 Implement deserializer for map mode and collection fields 2018-03-16 23:05:22 +01:00
Armin Ronacher b4dbae250b Added support for serialization of structs as maps 2018-03-16 23:05:22 +01:00
Armin Ronacher 5a91ac5ba5 Initial work on supporting structs as map with unknown field collection 2018-03-16 23:05:22 +01:00
David Tolnay 7ad836e6a9 Release 1.0.33 2018-03-15 10:03:42 -07:00
David Tolnay 72ecb9064c Fix parsing of qself in paths in attributes 2018-03-15 10:02:40 -07:00
David Tolnay 23c6eb3b40 Release 1.0.32 2018-03-13 11:31:26 -07:00
niklasad1 f9946ee0ca add some comments about alloc in no_std 2018-02-17 10:03:21 +01:00
Niklas Adolfsson a164f52315 Update README.md
Add some information about ```no_std``` because it was not obvious to me
2018-02-16 19:59:28 +01:00
25 changed files with 1686 additions and 139 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.31" # 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>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
+31
View File
@@ -1918,6 +1918,7 @@ where
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]
#[allow(deprecated)]
impl<'de, T> Deserialize<'de> for NonZero<T>
where
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>
+2 -1
View File
@@ -98,7 +98,8 @@
//! - Path
//! - PathBuf
//! - Range\<T\>
//! - NonZero\<T\> (unstable)
//! - NonZero\<T\> (unstable, deprecated)
//! - num::NonZero* (unstable)
//! - **Net types**:
//! - IpAddr
//! - Ipv4Addr
+5 -1
View File
@@ -79,7 +79,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.31")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.36")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
@@ -211,7 +211,11 @@ mod lib {
pub use std::sync::{Mutex, RwLock};
#[cfg(feature = "unstable")]
#[allow(deprecated)]
pub use core::nonzero::{NonZero, Zeroable};
#[cfg(feature = "unstable")]
pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize};
}
////////////////////////////////////////////////////////////////////////////////
+184 -9
View File
@@ -11,13 +11,13 @@ use lib::*;
use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
#[cfg(any(feature = "std", feature = "alloc"))]
use de::Unexpected;
use de::{Unexpected, MapAccess};
#[cfg(any(feature = "std", feature = "alloc"))]
pub use self::content::{Content, ContentDeserializer, ContentRefDeserializer,
InternallyTaggedUnitVisitor, TagContentOtherField,
TagContentOtherFieldVisitor, TagOrContentField, TagOrContentFieldVisitor,
TaggedContentVisitor, UntaggedUnitVisitor};
TaggedContentVisitor, UntaggedUnitVisitor, EnumDeserializer};
/// If the missing field is of type `Option<T>` then treat is as `None`,
/// otherwise it is an error.
@@ -269,6 +269,14 @@ mod content {
}
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 {
match *self {
Content::Bool(b) => Unexpected::Bool(b),
@@ -1118,11 +1126,7 @@ mod content {
}
};
visitor.visit_enum(EnumDeserializer {
variant: variant,
value: value,
err: PhantomData,
})
visitor.visit_enum(EnumDeserializer::new(variant, value))
}
fn deserialize_unit_struct<V>(
@@ -1170,7 +1174,7 @@ mod content {
}
}
struct EnumDeserializer<'de, E>
pub struct EnumDeserializer<'de, E>
where
E: de::Error,
{
@@ -1179,6 +1183,18 @@ mod content {
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>
where
E: de::Error,
@@ -1199,7 +1215,7 @@ mod content {
}
}
struct VariantDeserializer<'de, E>
pub struct VariantDeserializer<'de, E>
where
E: de::Error,
{
@@ -2062,3 +2078,162 @@ where
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
View File
@@ -11,7 +11,12 @@ use lib::*;
use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
#[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.
/// Not public API.
@@ -58,10 +63,11 @@ enum Unsupported {
ByteArray,
Optional,
Unit,
#[cfg(any(feature = "std", feature = "alloc"))]
UnitStruct,
Sequence,
Tuple,
TupleStruct,
#[cfg(not(any(feature = "std", feature = "alloc")))]
Enum,
}
@@ -76,10 +82,11 @@ impl Display for Unsupported {
Unsupported::ByteArray => formatter.write_str("a byte array"),
Unsupported::Optional => formatter.write_str("an optional"),
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::Tuple => formatter.write_str("a tuple"),
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
#[cfg(not(any(feature = "std", feature = "alloc")))]
Unsupported::Enum => formatter.write_str("an enum"),
}
}
@@ -459,7 +466,7 @@ mod content {
}
#[derive(Debug)]
enum Content {
pub enum Content {
Bool(bool),
U8(u8),
@@ -584,12 +591,12 @@ mod content {
}
}
struct ContentSerializer<E> {
pub struct ContentSerializer<E> {
error: PhantomData<E>,
}
impl<E> ContentSerializer<E> {
fn new() -> Self {
pub fn new() -> Self {
ContentSerializer { error: PhantomData }
}
}
@@ -804,7 +811,7 @@ mod content {
}
}
struct SerializeSeq<E> {
pub struct SerializeSeq<E> {
elements: Vec<Content>,
error: PhantomData<E>,
}
@@ -830,7 +837,7 @@ mod content {
}
}
struct SerializeTuple<E> {
pub struct SerializeTuple<E> {
elements: Vec<Content>,
error: PhantomData<E>,
}
@@ -856,7 +863,7 @@ mod content {
}
}
struct SerializeTupleStruct<E> {
pub struct SerializeTupleStruct<E> {
name: &'static str,
fields: Vec<Content>,
error: PhantomData<E>,
@@ -883,7 +890,7 @@ mod content {
}
}
struct SerializeTupleVariant<E> {
pub struct SerializeTupleVariant<E> {
name: &'static str,
variant_index: u32,
variant: &'static str,
@@ -917,7 +924,7 @@ mod content {
}
}
struct SerializeMap<E> {
pub struct SerializeMap<E> {
entries: Vec<(Content, Content)>,
key: Option<Content>,
error: PhantomData<E>,
@@ -967,7 +974,7 @@ mod content {
}
}
struct SerializeStruct<E> {
pub struct SerializeStruct<E> {
name: &'static str,
fields: Vec<(&'static str, Content)>,
error: PhantomData<E>,
@@ -994,7 +1001,7 @@ mod content {
}
}
struct SerializeStructVariant<E> {
pub struct SerializeStructVariant<E> {
name: &'static str,
variant_index: u32,
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(())
}
}
+27
View File
@@ -351,6 +351,7 @@ deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwne
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]
#[allow(deprecated)]
impl<T> Serialize for NonZero<T>
where
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>
where
T: Serialize + Copy,
+2 -1
View File
@@ -93,7 +93,8 @@
//! - Path
//! - PathBuf
//! - Range\<T\>
//! - NonZero\<T\> (unstable)
//! - NonZero\<T\> (unstable, deprecated)
//! - num::NonZero* (unstable)
//! - **Net types**:
//! - IpAddr
//! - Ipv4Addr
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.31" # 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>"]
license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -25,7 +25,7 @@ proc-macro = true
[dependencies]
proc-macro2 = "0.2"
quote = "0.4"
serde_derive_internals = { version = "=0.20.0", 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"] }
[dev-dependencies]
+303 -46
View File
@@ -268,7 +268,11 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<St
let code = match cont.data {
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) => {
deserialize_tuple_in_place(None, params, fields, &cont.attrs, None)
@@ -345,6 +349,8 @@ fn deserialize_tuple(
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();
assert!(!cattrs.has_flatten());
// 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
// getters then construct the target type directly.
@@ -440,6 +446,8 @@ fn deserialize_tuple_in_place(
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();
assert!(!cattrs.has_flatten());
let is_enum = variant_ident.is_some();
let expecting = match variant_ident {
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
@@ -522,6 +530,8 @@ fn deserialize_seq(
) -> Fragment {
let vars = (0..fields.len()).map(field_i as fn(_) -> _);
// XXX: do we need an error for flattening here?
let deserialized_count = fields
.iter()
.filter(|field| !field.attrs.skip_deserializing())
@@ -613,6 +623,8 @@ fn deserialize_seq_in_place(
) -> Fragment {
let vars = (0..fields.len()).map(field_i as fn(_) -> _);
// XXX: do we need an error for flattening here?
let deserialized_count = fields
.iter()
.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 (field_visitor, fields_stmt, visit_map) =
deserialize_struct_visitor(&type_path, params, fields, cattrs);
let (field_visitor, fields_stmt, visit_map) = if cattrs.has_flatten() {
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 fields_stmt = Stmts(fields_stmt);
let fields_stmt = fields_stmt.map(Stmts);
let visit_map = Stmts(visit_map);
let visitor_expr = quote! {
@@ -813,6 +828,10 @@ fn deserialize_struct(
quote! {
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
}
} else if cattrs.has_flatten() {
quote! {
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
}
} else {
let type_name = cattrs.name().deserialize_name();
quote! {
@@ -827,10 +846,10 @@ fn deserialize_struct(
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 {
Untagged::Yes => None,
Untagged::No => Some(quote! {
Untagged::No if !cattrs.has_flatten() => Some(quote! {
#[inline]
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<#delife>
@@ -838,6 +857,7 @@ fn deserialize_struct(
#visit_seq
}
}),
_ => None,
};
quote_block! {
@@ -878,9 +898,15 @@ fn deserialize_struct_in_place(
fields: &[Field],
cattrs: &attr::Container,
deserializer: Option<Tokens>,
) -> Fragment {
) -> Option<Fragment> {
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 = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
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 (field_visitor, fields_stmt, visit_map) =
deserialize_struct_in_place_visitor(params, fields, cattrs);
let (field_visitor, fields_stmt, visit_map) = deserialize_struct_as_struct_in_place_visitor(
params, fields, cattrs);
let field_visitor = Stmts(field_visitor);
let fields_stmt = Stmts(fields_stmt);
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 place_life = place_lifetime();
quote_block! {
Some(quote_block! {
#field_visitor
struct __Visitor #in_place_impl_generics #where_clause {
@@ -968,7 +995,7 @@ fn deserialize_struct_in_place(
#fields_stmt
#dispatch
}
})
}
fn deserialize_enum(
@@ -1688,12 +1715,16 @@ fn deserialize_untagged_newtype_variant(
fn deserialize_generated_identifier(
fields: &[(String, Ident)],
cattrs: &attr::Container,
is_variant: bool,
is_variant: bool
) -> Fragment {
let this = quote!(__Field);
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)
} else {
let ignore_variant = quote!(__ignore,);
@@ -1706,11 +1737,18 @@ fn deserialize_generated_identifier(
fields,
is_variant,
fallthrough,
cattrs.has_flatten(),
));
let lifetime = if cattrs.has_flatten() {
Some(quote!(<'de>))
} else {
None
};
quote_block! {
#[allow(non_camel_case_types)]
enum __Field {
enum __Field #lifetime {
#(#field_idents,)*
#ignore_variant
}
@@ -1718,12 +1756,12 @@ fn deserialize_generated_identifier(
struct __FieldVisitor;
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field;
type Value = __Field #lifetime;
#visitor_impl
}
impl<'de> _serde::Deserialize<'de> for __Field {
impl<'de> _serde::Deserialize<'de> for __Field #lifetime {
#[inline]
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
where __D: _serde::Deserializer<'de>
@@ -1804,6 +1842,7 @@ fn deserialize_custom_identifier(
&names_idents,
is_variant,
fallthrough,
false,
));
quote_block! {
@@ -1833,9 +1872,12 @@ fn deserialize_identifier(
fields: &[(String, Ident)],
is_variant: bool,
fallthrough: Option<Tokens>,
collect_other_fields: bool
) -> Fragment {
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_borrowed_bytes = fields.iter().map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
let constructors: &Vec<_> = &fields
.iter()
@@ -1852,28 +1894,129 @@ fn deserialize_identifier(
let variant_indices = 0u64..;
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
let visit_index = 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 visit_other = if collect_other_fields {
Some(quote! {
fn visit_bool<__E>(self, __value: bool) -> Result<Self::Value, __E>
where __E: _serde::de::Error
{
Ok(__Field::__other(_serde::private::de::Content::Bool(__value)))
}
}
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
} else {
let conversion = quote! {
Some(quote! {
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 {
@@ -1893,7 +2036,7 @@ fn deserialize_identifier(
_serde::export::Formatter::write_str(formatter, #expecting)
}
#visit_index
#visit_other
fn visit_str<__E>(self, __value: &str) -> _serde::export::Result<Self::Value, __E>
where __E: _serde::de::Error
@@ -1902,7 +2045,39 @@ fn deserialize_identifier(
#(
#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
#value_as_bytes_content
#fallthrough_arm
}
}
@@ -1922,12 +2098,14 @@ fn deserialize_identifier(
}
}
fn deserialize_struct_visitor(
fn deserialize_struct_as_struct_visitor(
struct_path: &Tokens,
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
) -> (Fragment, Fragment, Fragment) {
) -> (Fragment, Option<Fragment>, Fragment) {
assert!(!cattrs.has_flatten());
let field_names_idents: Vec<_> = fields
.iter()
.enumerate()
@@ -1946,7 +2124,27 @@ fn deserialize_struct_visitor(
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(
@@ -1965,7 +2163,7 @@ fn deserialize_map(
// Declare each field that will be deserialized.
let let_values = fields_names
.iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|&(field, ref name)| {
let field_ty = &field.ty;
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.
let value_arms = fields_names
.iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|&(field, ref name)| {
let deser_name = field.attrs.name().deserialize_name();
@@ -2008,7 +2218,15 @@ fn deserialize_map(
});
// 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
} else {
Some(quote! {
@@ -2038,7 +2256,7 @@ fn deserialize_map(
let extract_values = fields_names
.iter()
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|&(field, ref name)| {
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 ident = field.ident.expect("struct contains unnamed fields");
if field.attrs.skip_deserializing() {
@@ -2085,22 +2332,30 @@ fn deserialize_map(
quote_block! {
#(#let_values)*
#let_collect
#match_keys
#let_default
#(#extract_values)*
#(#extract_collected)*
#collected_deny_unknown_fields
_serde::export::Ok(#result)
}
}
#[cfg(feature = "deserialize_in_place")]
fn deserialize_struct_in_place_visitor(
fn deserialize_struct_as_struct_in_place_visitor(
params: &Parameters,
fields: &[Field],
cattrs: &attr::Container,
) -> (Fragment, Fragment, Fragment) {
assert!(!cattrs.has_flatten());
let field_names_idents: Vec<_> = fields
.iter()
.enumerate()
@@ -2128,6 +2383,8 @@ fn deserialize_map_in_place(
fields: &[Field],
cattrs: &attr::Container,
) -> Fragment {
assert!(!cattrs.has_flatten());
// Create the field names for the fields.
let fields_names: Vec<_> = fields
.iter()
@@ -2273,7 +2530,7 @@ fn field_i(i: usize) -> Ident {
fn wrap_deserialize_with(
params: &Parameters,
value_ty: &Tokens,
deserialize_with: &syn::Path,
deserialize_with: &syn::ExprPath,
) -> (Tokens, Tokens) {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
@@ -2308,7 +2565,7 @@ fn wrap_deserialize_with(
fn wrap_deserialize_field_with(
params: &Parameters,
field_ty: &syn::Type,
deserialize_with: &syn::Path,
deserialize_with: &syn::ExprPath,
) -> (Tokens, Tokens) {
wrap_deserialize_with(params, &quote!(#field_ty), deserialize_with)
}
@@ -2316,7 +2573,7 @@ fn wrap_deserialize_field_with(
fn wrap_deserialize_variant_with(
params: &Parameters,
variant: &Variant,
deserialize_with: &syn::Path,
deserialize_with: &syn::ExprPath,
) -> (Tokens, Tokens, Tokens) {
let this = &params.this;
let variant_ident = &variant.ident;
+2 -2
View File
@@ -22,11 +22,11 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.31")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.36")]
#![cfg_attr(feature = "cargo-clippy", allow(enum_variant_names, redundant_field_names,
too_many_arguments, used_underscore_binding))]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "256"]
#![recursion_limit = "512"]
#[macro_use]
extern crate quote;
+82 -17
View File
@@ -245,6 +245,14 @@ fn serialize_tuple_struct(
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
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(
fields,
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 {
assert!(variants.len() as u64 <= u64::from(u32::MAX));
@@ -859,6 +905,7 @@ fn serialize_struct_visitor(
.filter(|&field| !field.attrs.skip_serializing())
.map(|field| {
let field_ident = field.ident.expect("struct has unnamed field");
let mut field_expr = if is_enum {
quote!(#field_ident)
} else {
@@ -877,20 +924,33 @@ fn serialize_struct_visitor(
}
let span = Span::def_site().located_at(field.original.span());
let func = struct_trait.serialize_field(span);
let ser = quote! {
try!(#func(&mut __serde_state, #key_expr, #field_expr));
let ser = if field.attrs.flatten() {
quote! {
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 {
None => ser,
Some(skip) => {
let skip_func = struct_trait.skip_field(span);
quote! {
if !#skip {
#ser
} else {
try!(#skip_func(&mut __serde_state, #key_expr));
if let Some(skip_func) = struct_trait.skip_field(span) {
quote! {
if !#skip {
#ser
} else {
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(
params: &Parameters,
field_ty: &syn::Type,
serialize_with: &syn::Path,
serialize_with: &syn::ExprPath,
field_expr: &Tokens,
) -> Tokens {
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(
params: &Parameters,
serialize_with: &syn::Path,
serialize_with: &syn::ExprPath,
variant: &Variant,
) -> Tokens {
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(
params: &Parameters,
serialize_with: &syn::Path,
serialize_with: &syn::ExprPath,
field_tys: &[&syn::Type],
field_exprs: &[Tokens],
) -> Tokens {
@@ -1011,6 +1071,7 @@ fn get_member(params: &Parameters, field: &Field, member: &Member) -> Tokens {
}
enum StructTrait {
SerializeMap,
SerializeStruct,
SerializeStructVariant,
}
@@ -1018,6 +1079,9 @@ enum StructTrait {
impl StructTrait {
fn serialize_field(&self, span: Span) -> Tokens {
match *self {
StructTrait::SerializeMap => {
quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry)
}
StructTrait::SerializeStruct => {
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 {
StructTrait::SerializeStruct => {
StructTrait::SerializeMap => None,
StructTrait::SerializeStruct => Some({
quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)
}
StructTrait::SerializeStructVariant => {
}),
StructTrait::SerializeStructVariant => Some({
quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)
}
})
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive_internals"
version = "0.20.0" # 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>"]
license = "MIT/Apache-2.0"
description = "AST representation used by Serde derive macros. Unstable."
+9 -1
View File
@@ -48,7 +48,7 @@ pub enum Style {
impl<'a> 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 {
syn::Data::Enum(ref data) => {
@@ -63,6 +63,7 @@ impl<'a> Container<'a> {
}
};
let mut has_flatten = false;
match data {
Data::Enum(ref mut variants) => for variant in variants {
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 {
if field.attrs.flatten() {
has_flatten = true;
}
field.attrs.rename_by_rule(attrs.rename_all());
},
}
if has_flatten {
attrs.mark_has_flatten();
}
let item = Container {
ident: item.ident,
attrs: attrs,
+83 -38
View File
@@ -27,6 +27,7 @@ use proc_macro2::{Span, TokenStream, TokenNode, TokenTree};
pub use case::RenameRule;
#[derive(Copy, Clone)]
struct Attr<'c, T> {
cx: &'c Ctxt,
name: &'static str,
@@ -114,6 +115,7 @@ pub struct Container {
type_into: Option<syn::Type>,
remote: Option<syn::Path>,
identifier: Identifier,
has_flatten: bool,
}
/// Styles of representing an enum.
@@ -243,7 +245,7 @@ impl Container {
// Parse `#[serde(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 {
syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(_), .. }) => {
default.set(Default::Path(path));
@@ -330,7 +332,11 @@ impl Container {
// Parse `#[serde(remote = "...")]`
Meta(NameValue(ref m)) if m.ident == "remote" => {
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(),
remote: remote.get(),
identifier: decide_identifier(cx, item, &field_identifier, &variant_identifier),
has_flatten: false,
}
}
@@ -419,6 +426,14 @@ impl Container {
pub fn 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(
@@ -510,8 +525,8 @@ pub struct Variant {
skip_deserializing: bool,
skip_serializing: bool,
other: bool,
serialize_with: Option<syn::Path>,
deserialize_with: Option<syn::Path>,
serialize_with: Option<syn::ExprPath>,
deserialize_with: Option<syn::ExprPath>,
borrow: Option<syn::Meta>,
}
@@ -577,26 +592,26 @@ impl Variant {
// Parse `#[serde(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();
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);
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);
}
}
// Parse `#[serde(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);
}
}
// Parse `#[serde(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);
}
}
@@ -675,11 +690,11 @@ impl Variant {
self.other
}
pub fn serialize_with(&self) -> Option<&syn::Path> {
pub fn serialize_with(&self) -> Option<&syn::ExprPath> {
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()
}
}
@@ -691,14 +706,15 @@ pub struct Field {
de_renamed: bool,
skip_serializing: bool,
skip_deserializing: bool,
skip_serializing_if: Option<syn::Path>,
skip_serializing_if: Option<syn::ExprPath>,
default: Default,
serialize_with: Option<syn::Path>,
deserialize_with: Option<syn::Path>,
serialize_with: Option<syn::ExprPath>,
deserialize_with: Option<syn::ExprPath>,
ser_bound: Option<Vec<syn::WherePredicate>>,
de_bound: Option<Vec<syn::WherePredicate>>,
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.
@@ -708,7 +724,7 @@ pub enum Default {
/// The default is given by `std::default::Default::default()`.
Default,
/// The default is given by this function.
Path(syn::Path),
Path(syn::ExprPath),
}
impl Field {
@@ -732,6 +748,7 @@ impl Field {
let mut de_bound = Attr::none(cx, "bound");
let mut borrowed_lifetimes = Attr::none(cx, "borrow");
let mut getter = Attr::none(cx, "getter");
let mut flatten = BoolAttr::none(cx, "flatten");
let ident = match field.ident {
Some(ref ident) => ident.to_string(),
@@ -775,7 +792,7 @@ impl Field {
// Parse `#[serde(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));
}
}
@@ -798,33 +815,33 @@ impl Field {
// Parse `#[serde(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);
}
}
// Parse `#[serde(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);
}
}
// Parse `#[serde(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);
}
}
// Parse `#[serde(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();
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);
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);
}
}
@@ -873,11 +890,16 @@ impl Field {
// Parse `#[serde(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);
}
}
// Parse `#[serde(flatten)]`
Meta(Word(word)) if word == "flatten" => {
flatten.set_true();
}
Meta(ref meta_item) => {
cx.error(format!(
"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("de", 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) {
let mut path = syn::Path {
leading_colon: None,
@@ -931,7 +958,12 @@ impl Field {
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("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) {
// Types &str and &[u8] are always implicitly borrowed. No need for
@@ -960,6 +992,7 @@ impl Field {
de_bound: de_bound.get(),
borrowed_lifetimes: borrowed_lifetimes,
getter: getter.get(),
flatten: flatten.get(),
}
}
@@ -984,7 +1017,7 @@ impl Field {
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()
}
@@ -992,11 +1025,11 @@ impl Field {
&self.default
}
pub fn serialize_with(&self) -> Option<&syn::Path> {
pub fn serialize_with(&self) -> Option<&syn::ExprPath> {
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()
}
@@ -1012,9 +1045,13 @@ impl Field {
&self.borrowed_lifetimes
}
pub fn getter(&self) -> Option<&syn::Path> {
pub fn getter(&self) -> Option<&syn::ExprPath> {
self.getter.as_ref()
}
pub fn flatten(&self) -> bool {
self.flatten
}
}
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())))
}
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(
cx: &Ctxt,
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 {
is_primitive_path(ty, "str")
is_primitive_type(ty, "str")
}
fn is_slice_u8(ty: &syn::Type) -> bool {
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,
}
}
fn is_primitive_path(ty: &syn::Type, primitive: &str) -> bool {
fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool {
match *ty {
syn::Type::Path(ref ty) => {
ty.qself.is_none()
&& ty.path.leading_colon.is_none()
&& ty.path.segments.len() == 1
&& ty.path.segments[0].ident == primitive
&& ty.path.segments[0].arguments.is_empty()
ty.qself.is_none() && is_primitive_path(&ty.path, primitive)
}
_ => 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.
//
// For example a type `S<'a, 'b>` could borrow `'a` and `'b`. On the other hand
+1 -1
View File
@@ -7,7 +7,7 @@
// 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
#[allow(unused_imports)]
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std::str::FromStr;
+33
View File
@@ -14,6 +14,7 @@ use Ctxt;
/// object. Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &Container) {
check_getter(cx, cont);
check_flatten(cx, cont);
check_identifier(cx, cont);
check_variant_skip_attrs(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
/// variant of an enum that has the `field_identifier` attribute.
///
+1 -1
View File
@@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.20.0")]
#![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,
redundant_field_names))]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.31" # 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>"]
license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations"
+1 -1
View File
@@ -155,7 +155,7 @@
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.31")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.36")]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![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() {}
+532 -2
View File
@@ -12,12 +12,13 @@
extern crate serde_derive;
extern crate serde;
use std::collections::HashMap;
use self::serde::{Deserialize, Deserializer, Serialize, Serializer};
use self::serde::de::{self, Unexpected};
extern crate serde_test;
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens,
Token};
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens,
assert_ser_tokens_error, assert_tokens, Token};
trait MyDefault: Sized {
fn my_default() -> Self;
@@ -94,6 +95,56 @@ where
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]
fn test_default_struct() {
assert_de_tokens(
@@ -1267,3 +1318,482 @@ fn test_from_into_traits() {
assert_ser_tokens::<StructFromEnum>(&StructFromEnum(None), &[Token::None]);
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,
],
);
}
+11
View File
@@ -385,6 +385,10 @@ fn test_gen() {
s: vis::S,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "Self")]
struct RemoteSelf;
#[derive(Serialize, Deserialize)]
enum ExternallyTaggedVariantWith {
#[allow(dead_code)]
@@ -528,6 +532,13 @@ fn test_gen() {
marker: PhantomData<T>,
}
assert::<TypeMacro<X>>();
#[derive(Serialize)]
struct BigArray {
#[serde(serialize_with = "<[_]>::serialize")]
array: [u8; 256],
}
assert_ser::<BigArray>();
}
//////////////////////////////////////////////////////////////////////////