mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-23 03:38:00 +00:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 69dd3215f4 | |||
| a7a7a31809 | |||
| af9996aa9a | |||
| 0d4d47c398 | |||
| 30361ac6d0 | |||
| 3f75239bfb | |||
| 8dd5605a40 | |||
| f288a41768 | |||
| f4b78e202a | |||
| 0ddebe0317 | |||
| 9fc526b788 | |||
| a799ea171c | |||
| d6f07f2f47 | |||
| 8bba8447ef | |||
| 9db784bccd | |||
| 9317bc5afa | |||
| a185df1e77 | |||
| 1bdf5ecec4 | |||
| 59017aa19b | |||
| 6b4625dcbb | |||
| 6e01f220b1 | |||
| 64573319f9 | |||
| 3d64df6e87 | |||
| cc2558b0dc | |||
| 5c41661bce | |||
| dd6914a203 | |||
| 63623eb3b3 | |||
| ddc4b50d4d | |||
| b313f947dc | |||
| 16bc9fb99e | |||
| 34eaab00f7 | |||
| 6024e717fb | |||
| ef4dd6c0ec | |||
| f7ed967db1 | |||
| 613e46b0ee | |||
| b2d2e96267 | |||
| ae0373643c | |||
| 7aeabddd2f | |||
| 9df8f5ecc0 | |||
| c4fad2883b | |||
| 9cfcd78c87 | |||
| 4751627f1c |
+1
-1
@@ -5,7 +5,7 @@ environment:
|
||||
|
||||
install:
|
||||
# Install rust, x86_64-pc-windows-msvc host
|
||||
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||
- rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain %APPVEYOR_RUST_CHANNEL%
|
||||
- set PATH=C:\msys64\usr\bin;%PATH%;C:\Users\appveyor\.cargo\bin
|
||||
- rustc -vV
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "1.0.25" # remember to update html_root_url
|
||||
version = "1.0.30" # 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"
|
||||
|
||||
@@ -10,7 +10,7 @@ use lib::*;
|
||||
|
||||
macro_rules! int_to_int {
|
||||
($dst:ident, $n:ident) => (
|
||||
if $dst::MIN as i64 <= $n as i64 && $n as i64 <= $dst::MAX as i64 {
|
||||
if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 {
|
||||
Some($n as $dst)
|
||||
} else {
|
||||
None
|
||||
@@ -20,7 +20,7 @@ macro_rules! int_to_int {
|
||||
|
||||
macro_rules! int_to_uint {
|
||||
($dst:ident, $n:ident) => (
|
||||
if 0 <= $n && $n as u64 <= $dst::MAX as u64 {
|
||||
if 0 <= $n && $n as u64 <= $dst::max_value() as u64 {
|
||||
Some($n as $dst)
|
||||
} else {
|
||||
None
|
||||
@@ -30,7 +30,7 @@ macro_rules! int_to_uint {
|
||||
|
||||
macro_rules! uint_to {
|
||||
($dst:ident, $n:ident) => (
|
||||
if $n as u64 <= $dst::MAX as u64 {
|
||||
if $n as u64 <= $dst::max_value() as u64 {
|
||||
Some($n as $dst)
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -548,11 +548,11 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct PhantomDataVisitor<T> {
|
||||
struct PhantomDataVisitor<T: ?Sized> {
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'de, T> Visitor<'de> for PhantomDataVisitor<T> {
|
||||
impl<'de, T: ?Sized> Visitor<'de> for PhantomDataVisitor<T> {
|
||||
type Value = PhantomData<T>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
@@ -568,7 +568,7 @@ impl<'de, T> Visitor<'de> for PhantomDataVisitor<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for PhantomData<T> {
|
||||
impl<'de, T: ?Sized> Deserialize<'de> for PhantomData<T> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<PhantomData<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
|
||||
+1
-1
@@ -513,7 +513,7 @@ pub trait Deserialize<'de>: Sized {
|
||||
/// have been overwritten. Although whatever state that is will be
|
||||
/// memory-safe.
|
||||
///
|
||||
/// This is generally useful when repeateadly deserializing values that
|
||||
/// This is generally useful when repeatedly deserializing values that
|
||||
/// are processed one at a time, where the value of `self` doesn't matter
|
||||
/// when the next deserialization occurs.
|
||||
///
|
||||
|
||||
+6
-3
@@ -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.25")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.30")]
|
||||
// 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
|
||||
@@ -92,8 +92,8 @@
|
||||
// Whitelisted clippy lints
|
||||
#![cfg_attr(feature = "cargo-clippy",
|
||||
allow(cast_lossless, const_static_lifetime, doc_markdown, linkedlist,
|
||||
needless_pass_by_value, type_complexity, unreadable_literal,
|
||||
zero_prefixed_literal))]
|
||||
needless_pass_by_value, redundant_field_names, type_complexity,
|
||||
unreadable_literal, zero_prefixed_literal))]
|
||||
// Whitelisted clippy_pedantic lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||
// integer and float ser/de requires these sorts of casts
|
||||
@@ -104,6 +104,7 @@
|
||||
// simplifies some macros
|
||||
invalid_upcast_comparisons,
|
||||
// things are often more readable this way
|
||||
decimal_literal_representation,
|
||||
option_unwrap_used,
|
||||
result_unwrap_used,
|
||||
shadow_reuse,
|
||||
@@ -111,7 +112,9 @@
|
||||
stutter,
|
||||
use_self,
|
||||
// not practical
|
||||
many_single_char_names,
|
||||
missing_docs_in_private_items,
|
||||
similar_names,
|
||||
// alternative is not stable
|
||||
empty_enum,
|
||||
use_debug,
|
||||
|
||||
@@ -188,7 +188,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(CowBytesVisitor)
|
||||
deserializer.deserialize_bytes(CowBytesVisitor)
|
||||
}
|
||||
|
||||
pub mod size_hint {
|
||||
|
||||
@@ -111,7 +111,7 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T> Serialize for PhantomData<T> {
|
||||
impl<T: ?Sized> Serialize for PhantomData<T> {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "1.0.25" # remember to update html_root_url
|
||||
version = "1.0.30" # 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)]"
|
||||
@@ -23,9 +23,10 @@ name = "serde_derive"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "0.3.8"
|
||||
serde_derive_internals = { version = "=0.18.1", default-features = false, path = "../serde_derive_internals" }
|
||||
syn = { version = "0.11", features = ["visit"] }
|
||||
proc-macro2 = "0.2"
|
||||
quote = "0.4"
|
||||
serde_derive_internals = { version = "=0.20.0", default-features = false, path = "../serde_derive_internals" }
|
||||
syn = { version = "0.12", features = ["visit"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0", path = "../serde" }
|
||||
|
||||
+162
-98
@@ -9,27 +9,30 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use syn::{self, visit};
|
||||
use syn::punctuated::Punctuated;
|
||||
|
||||
use internals::ast::{Body, Container};
|
||||
use internals::ast::{Data, Container};
|
||||
use internals::attr;
|
||||
|
||||
macro_rules! path {
|
||||
($($path:tt)+) => {
|
||||
syn::parse_path(quote!($($path)+).as_str()).unwrap()
|
||||
};
|
||||
}
|
||||
use proc_macro2::{Span, Term};
|
||||
|
||||
// Remove the default from every type parameter because in the generated impls
|
||||
// they look like associated types: "error: associated type bindings are not
|
||||
// allowed here".
|
||||
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
|
||||
syn::Generics {
|
||||
ty_params: generics
|
||||
.ty_params
|
||||
params: generics
|
||||
.params
|
||||
.iter()
|
||||
.map(|ty_param| syn::TyParam {
|
||||
default: None,
|
||||
..ty_param.clone()
|
||||
.map(|param| match *param {
|
||||
syn::GenericParam::Type(ref param) => {
|
||||
syn::GenericParam::Type(syn::TypeParam {
|
||||
eq_token: None,
|
||||
default: None,
|
||||
..param.clone()
|
||||
})
|
||||
}
|
||||
_ => param.clone(),
|
||||
})
|
||||
.collect(),
|
||||
..generics.clone()
|
||||
@@ -41,10 +44,17 @@ pub fn with_where_predicates(
|
||||
predicates: &[syn::WherePredicate],
|
||||
) -> syn::Generics {
|
||||
let mut generics = generics.clone();
|
||||
generics
|
||||
.where_clause
|
||||
if generics.where_clause.is_none() {
|
||||
generics.where_clause = Some(syn::WhereClause {
|
||||
where_token: Default::default(),
|
||||
predicates: Punctuated::new(),
|
||||
});
|
||||
}
|
||||
generics.where_clause
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.predicates
|
||||
.extend_from_slice(predicates);
|
||||
.extend(predicates.into_iter().cloned());
|
||||
generics
|
||||
}
|
||||
|
||||
@@ -56,13 +66,23 @@ pub fn with_where_predicates_from_fields<F>(
|
||||
where
|
||||
F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
|
||||
{
|
||||
let predicates = cont.body
|
||||
let predicates = cont.data
|
||||
.all_fields()
|
||||
.flat_map(|field| from_field(&field.attrs))
|
||||
.flat_map(|predicates| predicates.to_vec());
|
||||
|
||||
let mut generics = generics.clone();
|
||||
generics.where_clause.predicates.extend(predicates);
|
||||
if generics.where_clause.is_none() {
|
||||
generics.where_clause = Some(syn::WhereClause {
|
||||
where_token: Default::default(),
|
||||
predicates: Punctuated::new(),
|
||||
});
|
||||
}
|
||||
generics.where_clause
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.predicates
|
||||
.extend(predicates);
|
||||
generics
|
||||
}
|
||||
|
||||
@@ -95,22 +115,22 @@ where
|
||||
// them.
|
||||
relevant_ty_params: HashSet<syn::Ident>,
|
||||
}
|
||||
impl visit::Visitor for FindTyParams {
|
||||
impl<'ast> visit::Visit<'ast> for FindTyParams {
|
||||
fn visit_path(&mut self, path: &syn::Path) {
|
||||
if let Some(seg) = path.segments.last() {
|
||||
if seg.ident == "PhantomData" {
|
||||
if seg.into_value().ident == "PhantomData" {
|
||||
// Hardcoded exception, because PhantomData<T> implements
|
||||
// Serialize and Deserialize whether or not T implements it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
if !path.global && path.segments.len() == 1 {
|
||||
let id = path.segments[0].ident.clone();
|
||||
if path.leading_colon.is_none() && path.segments.len() == 1 {
|
||||
let id = path.segments[0].ident;
|
||||
if self.all_ty_params.contains(&id) {
|
||||
self.relevant_ty_params.insert(id);
|
||||
}
|
||||
}
|
||||
visit::walk_path(self, path);
|
||||
visit::visit_path(self, path);
|
||||
}
|
||||
|
||||
// Type parameter should not be considered used by a macro path.
|
||||
@@ -119,61 +139,79 @@ where
|
||||
// mac: T!(),
|
||||
// marker: PhantomData<T>,
|
||||
// }
|
||||
fn visit_mac(&mut self, _mac: &syn::Mac) {}
|
||||
fn visit_macro(&mut self, _mac: &syn::Macro) {}
|
||||
}
|
||||
|
||||
let all_ty_params: HashSet<_> = generics
|
||||
.ty_params
|
||||
.params
|
||||
.iter()
|
||||
.map(|ty_param| ty_param.ident.clone())
|
||||
.filter_map(|param| match *param {
|
||||
syn::GenericParam::Type(ref param) => Some(param.ident),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut visitor = FindTyParams {
|
||||
all_ty_params: all_ty_params,
|
||||
relevant_ty_params: HashSet::new(),
|
||||
};
|
||||
match cont.body {
|
||||
Body::Enum(ref variants) => for variant in variants.iter() {
|
||||
match cont.data {
|
||||
Data::Enum(ref variants) => for variant in variants.iter() {
|
||||
let relevant_fields = variant
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
|
||||
for field in relevant_fields {
|
||||
visit::walk_ty(&mut visitor, field.ty);
|
||||
visit::visit_type(&mut visitor, field.ty);
|
||||
}
|
||||
},
|
||||
Body::Struct(_, ref fields) => {
|
||||
Data::Struct(_, ref fields) => {
|
||||
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
|
||||
visit::walk_ty(&mut visitor, field.ty);
|
||||
visit::visit_type(&mut visitor, field.ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let new_predicates = generics
|
||||
.ty_params
|
||||
.params
|
||||
.iter()
|
||||
.map(|ty_param| ty_param.ident.clone())
|
||||
.filter_map(|param| match *param {
|
||||
syn::GenericParam::Type(ref param) => Some(param.ident),
|
||||
_ => None,
|
||||
})
|
||||
.filter(|id| visitor.relevant_ty_params.contains(id))
|
||||
.map(|id| {
|
||||
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
|
||||
bound_lifetimes: Vec::new(),
|
||||
syn::WherePredicate::Type(syn::PredicateType {
|
||||
lifetimes: None,
|
||||
// the type parameter that is being bounded e.g. T
|
||||
bounded_ty: syn::Ty::Path(None, id.into()),
|
||||
bounded_ty: syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
path: id.into(),
|
||||
}),
|
||||
colon_token: Default::default(),
|
||||
// the bound e.g. Serialize
|
||||
bounds: vec![
|
||||
syn::TyParamBound::Trait(
|
||||
syn::PolyTraitRef {
|
||||
bound_lifetimes: Vec::new(),
|
||||
trait_ref: bound.clone(),
|
||||
},
|
||||
syn::TraitBoundModifier::None,
|
||||
),
|
||||
],
|
||||
syn::TypeParamBound::Trait(syn::TraitBound {
|
||||
modifier: syn::TraitBoundModifier::None,
|
||||
lifetimes: None,
|
||||
path: bound.clone(),
|
||||
}),
|
||||
].into_iter().collect(),
|
||||
})
|
||||
});
|
||||
|
||||
let mut generics = generics.clone();
|
||||
generics.where_clause.predicates.extend(new_predicates);
|
||||
if generics.where_clause.is_none() {
|
||||
generics.where_clause = Some(syn::WhereClause {
|
||||
where_token: Default::default(),
|
||||
predicates: Punctuated::new(),
|
||||
});
|
||||
}
|
||||
generics.where_clause
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.predicates
|
||||
.extend(new_predicates);
|
||||
generics
|
||||
}
|
||||
|
||||
@@ -183,76 +221,102 @@ pub fn with_self_bound(
|
||||
bound: &syn::Path,
|
||||
) -> syn::Generics {
|
||||
let mut generics = generics.clone();
|
||||
generics
|
||||
.where_clause
|
||||
if generics.where_clause.is_none() {
|
||||
generics.where_clause = Some(syn::WhereClause {
|
||||
where_token: Default::default(),
|
||||
predicates: Punctuated::new(),
|
||||
});
|
||||
}
|
||||
generics.where_clause
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.predicates
|
||||
.push(syn::WherePredicate::BoundPredicate(
|
||||
syn::WhereBoundPredicate {
|
||||
bound_lifetimes: Vec::new(),
|
||||
// the type that is being bounded e.g. MyStruct<'a, T>
|
||||
bounded_ty: type_of_item(cont),
|
||||
// the bound e.g. Default
|
||||
bounds: vec![
|
||||
syn::TyParamBound::Trait(
|
||||
syn::PolyTraitRef {
|
||||
bound_lifetimes: Vec::new(),
|
||||
trait_ref: bound.clone(),
|
||||
},
|
||||
syn::TraitBoundModifier::None,
|
||||
),
|
||||
],
|
||||
},
|
||||
));
|
||||
.push(syn::WherePredicate::Type(syn::PredicateType {
|
||||
lifetimes: None,
|
||||
// the type that is being bounded e.g. MyStruct<'a, T>
|
||||
bounded_ty: type_of_item(cont),
|
||||
colon_token: Default::default(),
|
||||
// the bound e.g. Default
|
||||
bounds: vec![
|
||||
syn::TypeParamBound::Trait(syn::TraitBound {
|
||||
modifier: syn::TraitBoundModifier::None,
|
||||
lifetimes: None,
|
||||
path: bound.clone(),
|
||||
}),
|
||||
].into_iter().collect(),
|
||||
}));
|
||||
generics
|
||||
}
|
||||
|
||||
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
|
||||
let mut generics = generics.clone();
|
||||
|
||||
for lifetime_def in &mut generics.lifetimes {
|
||||
lifetime_def.bounds.push(syn::Lifetime::new(lifetime));
|
||||
}
|
||||
|
||||
for ty_param in &mut generics.ty_params {
|
||||
ty_param
|
||||
.bounds
|
||||
.push(syn::TyParamBound::Region(syn::Lifetime::new(lifetime)));
|
||||
}
|
||||
|
||||
generics.lifetimes.push(syn::LifetimeDef {
|
||||
let bound = syn::Lifetime::new(Term::intern(lifetime), Span::def_site());
|
||||
let def = syn::LifetimeDef {
|
||||
attrs: Vec::new(),
|
||||
lifetime: syn::Lifetime::new(lifetime),
|
||||
bounds: Vec::new(),
|
||||
});
|
||||
lifetime: bound,
|
||||
colon_token: None,
|
||||
bounds: Punctuated::new(),
|
||||
};
|
||||
|
||||
generics
|
||||
let params = Some(syn::GenericParam::Lifetime(def))
|
||||
.into_iter()
|
||||
.chain(generics.params
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|mut param| {
|
||||
match param {
|
||||
syn::GenericParam::Lifetime(ref mut param) => {
|
||||
param.bounds.push(bound);
|
||||
}
|
||||
syn::GenericParam::Type(ref mut param) => {
|
||||
param.bounds.push(syn::TypeParamBound::Lifetime(bound));
|
||||
}
|
||||
syn::GenericParam::Const(_) => {}
|
||||
}
|
||||
param
|
||||
}))
|
||||
.collect();
|
||||
|
||||
syn::Generics {
|
||||
params: params,
|
||||
..generics.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn type_of_item(cont: &Container) -> syn::Ty {
|
||||
syn::Ty::Path(
|
||||
None,
|
||||
syn::Path {
|
||||
global: false,
|
||||
fn type_of_item(cont: &Container) -> syn::Type {
|
||||
syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
path: syn::Path {
|
||||
leading_colon: None,
|
||||
segments: vec![
|
||||
syn::PathSegment {
|
||||
ident: cont.ident.clone(),
|
||||
parameters: syn::PathParameters::AngleBracketed(
|
||||
syn::AngleBracketedParameterData {
|
||||
lifetimes: cont.generics
|
||||
.lifetimes
|
||||
ident: cont.ident,
|
||||
arguments: syn::PathArguments::AngleBracketed(
|
||||
syn::AngleBracketedGenericArguments {
|
||||
colon2_token: None,
|
||||
lt_token: Default::default(),
|
||||
args: cont.generics
|
||||
.params
|
||||
.iter()
|
||||
.map(|def| def.lifetime.clone())
|
||||
.map(|param| match *param {
|
||||
syn::GenericParam::Type(ref param) => {
|
||||
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
path: param.ident.into(),
|
||||
}))
|
||||
}
|
||||
syn::GenericParam::Lifetime(ref param) => {
|
||||
syn::GenericArgument::Lifetime(param.lifetime)
|
||||
}
|
||||
syn::GenericParam::Const(_) => {
|
||||
panic!("Serde does not support const generics yet");
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
types: cont.generics
|
||||
.ty_params
|
||||
.iter()
|
||||
.map(|param| syn::Ty::Path(None, param.ident.clone().into()))
|
||||
.collect(),
|
||||
bindings: Vec::new(),
|
||||
gt_token: Default::default(),
|
||||
},
|
||||
),
|
||||
},
|
||||
],
|
||||
].into_iter().collect(),
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
+187
-130
@@ -6,12 +6,15 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use syn::{self, Ident};
|
||||
use quote::{self, ToTokens, Tokens};
|
||||
use syn::{self, Ident, Index, Member};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::spanned::Spanned;
|
||||
use quote::{ToTokens, Tokens};
|
||||
use proc_macro2::{Literal, Span, Term};
|
||||
|
||||
use bound;
|
||||
use fragment::{Expr, Fragment, Match, Stmts};
|
||||
use internals::ast::{Body, Container, Field, Style, Variant};
|
||||
use internals::ast::{Data, Container, Field, Style, Variant};
|
||||
use internals::{self, attr};
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
@@ -24,15 +27,16 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
|
||||
let ident = &cont.ident;
|
||||
let params = Parameters::new(&cont);
|
||||
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms);
|
||||
let dummy_const = Ident::new(format!("_IMPL_DESERIALIZE_FOR_{}", ident));
|
||||
let dummy_const = Ident::new(&format!("_IMPL_DESERIALIZE_FOR_{}", ident), Span::def_site());
|
||||
let body = Stmts(deserialize_body(&cont, ¶ms));
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||
let vis = &input.vis;
|
||||
let fun = quote_spanned!(Span::call_site()=> deserialize);
|
||||
quote! {
|
||||
impl #de_impl_generics #ident #ty_generics #where_clause {
|
||||
#vis fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
|
||||
#vis fn #fun<__D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
|
||||
where __D: _serde::Deserializer<#delife>
|
||||
{
|
||||
#body
|
||||
@@ -89,14 +93,14 @@ struct Parameters {
|
||||
|
||||
impl Parameters {
|
||||
fn new(cont: &Container) -> Self {
|
||||
let local = cont.ident.clone();
|
||||
let local = cont.ident;
|
||||
let this = match cont.attrs.remote() {
|
||||
Some(remote) => remote.clone(),
|
||||
None => cont.ident.clone().into(),
|
||||
None => cont.ident.into(),
|
||||
};
|
||||
let borrowed = borrowed_lifetimes(cont);
|
||||
let generics = build_generics(cont, &borrowed);
|
||||
let has_getter = cont.body.has_getter();
|
||||
let has_getter = cont.data.has_getter();
|
||||
|
||||
Parameters {
|
||||
local: local,
|
||||
@@ -110,7 +114,7 @@ impl Parameters {
|
||||
/// Type name to use in error messages and `&'static str` arguments to
|
||||
/// various Deserializer methods.
|
||||
fn type_name(&self) -> &str {
|
||||
self.this.segments.last().unwrap().ident.as_ref()
|
||||
self.this.segments.last().unwrap().value().ident.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +131,7 @@ fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generi
|
||||
None => {
|
||||
let generics = match *cont.attrs.default() {
|
||||
attr::Default::Default => {
|
||||
bound::with_self_bound(cont, &generics, &path!(_serde::export::Default))
|
||||
bound::with_self_bound(cont, &generics, &parse_quote!(_serde::export::Default))
|
||||
}
|
||||
attr::Default::None | attr::Default::Path(_) => generics,
|
||||
};
|
||||
@@ -137,14 +141,14 @@ fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generi
|
||||
cont,
|
||||
&generics,
|
||||
needs_deserialize_bound,
|
||||
&path!(_serde::Deserialize<#delife>),
|
||||
&parse_quote!(_serde::Deserialize<#delife>),
|
||||
);
|
||||
|
||||
bound::with_bound(
|
||||
cont,
|
||||
&generics,
|
||||
requires_default,
|
||||
&path!(_serde::export::Default),
|
||||
&parse_quote!(_serde::export::Default),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -162,7 +166,11 @@ fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>)
|
||||
// Fields with a `default` attribute (not `default=...`), and fields with a
|
||||
// `skip_deserializing` attribute that do not also have `default=...`.
|
||||
fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bool {
|
||||
field.default() == &attr::Default::Default
|
||||
if let attr::Default::Default = *field.default() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
enum BorrowedLifetimes {
|
||||
@@ -173,8 +181,8 @@ enum BorrowedLifetimes {
|
||||
impl BorrowedLifetimes {
|
||||
fn de_lifetime(&self) -> syn::Lifetime {
|
||||
match *self {
|
||||
BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new("'de"),
|
||||
BorrowedLifetimes::Static => syn::Lifetime::new("'static"),
|
||||
BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new(Term::intern("'de"), Span::def_site()),
|
||||
BorrowedLifetimes::Static => syn::Lifetime::new(Term::intern("'static"), Span::def_site()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +190,8 @@ impl BorrowedLifetimes {
|
||||
match *self {
|
||||
BorrowedLifetimes::Borrowed(ref bounds) => Some(syn::LifetimeDef {
|
||||
attrs: Vec::new(),
|
||||
lifetime: syn::Lifetime::new("'de"),
|
||||
lifetime: syn::Lifetime::new(Term::intern("'de"), Span::def_site()),
|
||||
colon_token: None,
|
||||
bounds: bounds.iter().cloned().collect(),
|
||||
}),
|
||||
BorrowedLifetimes::Static => None,
|
||||
@@ -201,12 +210,12 @@ impl BorrowedLifetimes {
|
||||
// and we use plain `'static` instead of `'de`.
|
||||
fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
|
||||
let mut lifetimes = BTreeSet::new();
|
||||
for field in cont.body.all_fields() {
|
||||
for field in cont.data.all_fields() {
|
||||
if !field.attrs.skip_deserializing() {
|
||||
lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned());
|
||||
}
|
||||
}
|
||||
if lifetimes.iter().any(|b| b.ident == "'static") {
|
||||
if lifetimes.iter().any(|b| b.to_string() == "'static") {
|
||||
BorrowedLifetimes::Static
|
||||
} else {
|
||||
BorrowedLifetimes::Borrowed(lifetimes)
|
||||
@@ -214,31 +223,31 @@ fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
|
||||
}
|
||||
|
||||
fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||
if let Some(from_type) = cont.attrs.from_type() {
|
||||
deserialize_from(from_type)
|
||||
if let Some(type_from) = cont.attrs.type_from() {
|
||||
deserialize_from(type_from)
|
||||
} else if let attr::Identifier::No = cont.attrs.identifier() {
|
||||
match cont.body {
|
||||
Body::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs),
|
||||
Body::Struct(Style::Struct, ref fields) => {
|
||||
match cont.data {
|
||||
Data::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs),
|
||||
Data::Struct(Style::Struct, ref fields) => {
|
||||
if fields.iter().any(|field| field.ident.is_none()) {
|
||||
panic!("struct has unnamed fields");
|
||||
}
|
||||
deserialize_struct(None, params, fields, &cont.attrs, None, Untagged::No)
|
||||
deserialize_struct(None, params, fields, &cont.attrs, None, &Untagged::No)
|
||||
}
|
||||
Body::Struct(Style::Tuple, ref fields) | Body::Struct(Style::Newtype, ref fields) => {
|
||||
Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => {
|
||||
if fields.iter().any(|field| field.ident.is_some()) {
|
||||
panic!("tuple struct has named fields");
|
||||
}
|
||||
deserialize_tuple(None, params, fields, &cont.attrs, None)
|
||||
}
|
||||
Body::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs),
|
||||
Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs),
|
||||
}
|
||||
} else {
|
||||
match cont.body {
|
||||
Body::Enum(ref variants) => {
|
||||
match cont.data {
|
||||
Data::Enum(ref variants) => {
|
||||
deserialize_custom_identifier(params, variants, &cont.attrs)
|
||||
}
|
||||
Body::Struct(_, _) => unreachable!("checked in serde_derive_internals"),
|
||||
Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -249,22 +258,22 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<St
|
||||
// deserialize_in_place for remote derives.
|
||||
assert!(!params.has_getter);
|
||||
|
||||
if cont.attrs.from_type().is_some() || cont.attrs.identifier().is_some()
|
||||
|| cont.body
|
||||
if cont.attrs.type_from().is_some() || cont.attrs.identifier().is_some()
|
||||
|| cont.data
|
||||
.all_fields()
|
||||
.all(|f| f.attrs.deserialize_with().is_some())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let code = match cont.body {
|
||||
Body::Struct(Style::Struct, ref fields) => {
|
||||
deserialize_struct_in_place(None, params, fields, &cont.attrs, None, Untagged::No)
|
||||
let code = match cont.data {
|
||||
Data::Struct(Style::Struct, ref fields) => {
|
||||
deserialize_struct_in_place(None, params, fields, &cont.attrs, None)
|
||||
}
|
||||
Body::Struct(Style::Tuple, ref fields) | Body::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)
|
||||
}
|
||||
Body::Enum(_) | Body::Struct(Style::Unit, _) => {
|
||||
Data::Enum(_) | Data::Struct(Style::Unit, _) => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
@@ -288,10 +297,10 @@ fn deserialize_in_place_body(_cont: &Container, _params: &Parameters) -> Option<
|
||||
None
|
||||
}
|
||||
|
||||
fn deserialize_from(from_type: &syn::Ty) -> Fragment {
|
||||
fn deserialize_from(type_from: &syn::Type) -> Fragment {
|
||||
quote_block! {
|
||||
_serde::export::Result::map(
|
||||
<#from_type as _serde::Deserialize>::deserialize(__deserializer),
|
||||
<#type_from as _serde::Deserialize>::deserialize(__deserializer),
|
||||
_serde::export::From::from)
|
||||
}
|
||||
}
|
||||
@@ -522,7 +531,7 @@ fn deserialize_seq(
|
||||
let mut index_in_seq = 0usize;
|
||||
let let_values = vars.clone().zip(fields).map(|(var, field)| {
|
||||
if field.attrs.skip_deserializing() {
|
||||
let default = Expr(expr_is_missing(&field, cattrs));
|
||||
let default = Expr(expr_is_missing(field, cattrs));
|
||||
quote! {
|
||||
let #var = #default;
|
||||
}
|
||||
@@ -530,7 +539,9 @@ fn deserialize_seq(
|
||||
let visit = match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
let field_ty = &field.ty;
|
||||
quote!(try!(_serde::de::SeqAccess::next_element::<#field_ty>(&mut __seq)))
|
||||
let span = Span::def_site().located_at(field.original.span());
|
||||
let func = quote_spanned!(span=> _serde::de::SeqAccess::next_element::<#field_ty>);
|
||||
quote!(try!(#func(&mut __seq)))
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
@@ -557,11 +568,11 @@ fn deserialize_seq(
|
||||
|
||||
let mut result = if is_struct {
|
||||
let names = fields.iter().map(|f| &f.ident);
|
||||
quote! {
|
||||
quote_spanned! {Span::call_site()=>
|
||||
#type_path { #( #names: #vars ),* }
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
quote_spanned! {Span::call_site()=>
|
||||
#type_path ( #(#vars),* )
|
||||
}
|
||||
};
|
||||
@@ -616,13 +627,17 @@ fn deserialize_seq_in_place(
|
||||
// If there's no field name, assume we're a tuple-struct and use a numeric index
|
||||
let field_name = field
|
||||
.ident
|
||||
.clone()
|
||||
.unwrap_or_else(|| Ident::new(field_index.to_string()));
|
||||
.map(Member::Named)
|
||||
.unwrap_or_else(|| Member::Unnamed(Index {
|
||||
index: field_index as u32,
|
||||
span: Span::call_site(),
|
||||
}));
|
||||
|
||||
let dot = quote_spanned!(Span::call_site()=> .);
|
||||
if field.attrs.skip_deserializing() {
|
||||
let default = Expr(expr_is_missing(&field, cattrs));
|
||||
let default = Expr(expr_is_missing(field, cattrs));
|
||||
quote! {
|
||||
self.place.#field_name = #default;
|
||||
self.place #dot #field_name = #default;
|
||||
}
|
||||
} else {
|
||||
let return_invalid_length = quote! {
|
||||
@@ -632,7 +647,7 @@ fn deserialize_seq_in_place(
|
||||
None => {
|
||||
quote! {
|
||||
if let _serde::export::None = try!(_serde::de::SeqAccess::next_element_seed(&mut __seq,
|
||||
_serde::private::de::InPlaceSeed(&mut self.place.#field_name)))
|
||||
_serde::private::de::InPlaceSeed(&mut self.place #dot #field_name)))
|
||||
{
|
||||
#return_invalid_length
|
||||
}
|
||||
@@ -645,7 +660,7 @@ fn deserialize_seq_in_place(
|
||||
#wrapper
|
||||
match try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)) {
|
||||
_serde::export::Some(__wrap) => {
|
||||
self.place.#field_name = __wrap.value;
|
||||
self.place #dot #field_name = __wrap.value;
|
||||
}
|
||||
_serde::export::None => {
|
||||
#return_invalid_length
|
||||
@@ -701,7 +716,7 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
|
||||
}
|
||||
};
|
||||
|
||||
let mut result = quote!(#type_path(#value));
|
||||
let mut result = quote_spanned!(Span::call_site()=> #type_path(#value));
|
||||
if params.has_getter {
|
||||
let this = ¶ms.this;
|
||||
result = quote! {
|
||||
@@ -726,12 +741,13 @@ fn deserialize_newtype_struct_in_place(params: &Parameters, field: &Field) -> To
|
||||
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let elem = quote_spanned!(Span::call_site()=> .0);
|
||||
quote! {
|
||||
#[inline]
|
||||
fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result<Self::Value, __E::Error>
|
||||
where __E: _serde::Deserializer<#delife>
|
||||
{
|
||||
_serde::Deserialize::deserialize_in_place(__e, &mut self.place.0)
|
||||
_serde::Deserialize::deserialize_in_place(__e, &mut self.place #elem)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -747,7 +763,7 @@ fn deserialize_struct(
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Option<Tokens>,
|
||||
untagged: Untagged,
|
||||
untagged: &Untagged,
|
||||
) -> Fragment {
|
||||
let is_enum = variant_ident.is_some();
|
||||
|
||||
@@ -778,7 +794,7 @@ 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);
|
||||
deserialize_struct_visitor(&type_path, params, fields, cattrs);
|
||||
let field_visitor = Stmts(field_visitor);
|
||||
let fields_stmt = Stmts(fields_stmt);
|
||||
let visit_map = Stmts(visit_map);
|
||||
@@ -812,7 +828,7 @@ fn deserialize_struct(
|
||||
};
|
||||
|
||||
// untagged struct variants do not get a visit_seq method
|
||||
let visit_seq = match untagged {
|
||||
let visit_seq = match *untagged {
|
||||
Untagged::Yes => None,
|
||||
Untagged::No => Some(quote! {
|
||||
#[inline]
|
||||
@@ -862,7 +878,6 @@ fn deserialize_struct_in_place(
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Option<Tokens>,
|
||||
untagged: Untagged,
|
||||
) -> Fragment {
|
||||
let is_enum = variant_ident.is_some();
|
||||
|
||||
@@ -912,17 +927,13 @@ fn deserialize_struct_in_place(
|
||||
quote!(mut __seq)
|
||||
};
|
||||
|
||||
// untagged struct variants do not get a visit_seq method
|
||||
let visit_seq = match untagged {
|
||||
Untagged::Yes => None,
|
||||
Untagged::No => Some(quote! {
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::SeqAccess<#delife>
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
}),
|
||||
let visit_seq = quote! {
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::SeqAccess<#delife>
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
};
|
||||
|
||||
let in_place_impl_generics = de_impl_generics.in_place();
|
||||
@@ -1007,7 +1018,7 @@ fn deserialize_externally_tagged_enum(
|
||||
};
|
||||
|
||||
let variant_visitor = Stmts(deserialize_generated_identifier(
|
||||
variant_names_idents,
|
||||
&variant_names_idents,
|
||||
cattrs,
|
||||
true,
|
||||
));
|
||||
@@ -1106,7 +1117,7 @@ fn deserialize_internally_tagged_enum(
|
||||
};
|
||||
|
||||
let variant_visitor = Stmts(deserialize_generated_identifier(
|
||||
variant_names_idents,
|
||||
&variant_names_idents,
|
||||
cattrs,
|
||||
true,
|
||||
));
|
||||
@@ -1175,12 +1186,12 @@ fn deserialize_adjacently_tagged_enum(
|
||||
};
|
||||
|
||||
let variant_visitor = Stmts(deserialize_generated_identifier(
|
||||
variant_names_idents,
|
||||
&variant_names_idents,
|
||||
cattrs,
|
||||
true,
|
||||
));
|
||||
|
||||
let ref variant_arms: Vec<_> = variants
|
||||
let variant_arms: &Vec<_> = &variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
|
||||
@@ -1488,7 +1499,7 @@ fn deserialize_externally_tagged_variant(
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.deserialize_with() {
|
||||
let (wrapper, wrapper_ty, unwrap_fn) =
|
||||
wrap_deserialize_variant_with(params, &variant, path);
|
||||
wrap_deserialize_variant_with(params, variant, path);
|
||||
return quote_block! {
|
||||
#wrapper
|
||||
_serde::export::Result::map(
|
||||
@@ -1518,7 +1529,7 @@ fn deserialize_externally_tagged_variant(
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
None,
|
||||
Untagged::No,
|
||||
&Untagged::No,
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -1549,7 +1560,7 @@ fn deserialize_internally_tagged_variant(
|
||||
variant_ident,
|
||||
params,
|
||||
&variant.fields[0],
|
||||
deserializer,
|
||||
&deserializer,
|
||||
),
|
||||
Style::Struct => deserialize_struct(
|
||||
Some(variant_ident),
|
||||
@@ -1557,7 +1568,7 @@ fn deserialize_internally_tagged_variant(
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
Some(deserializer),
|
||||
Untagged::No,
|
||||
&Untagged::No,
|
||||
),
|
||||
Style::Tuple => unreachable!("checked in serde_derive_internals"),
|
||||
}
|
||||
@@ -1571,7 +1582,7 @@ fn deserialize_untagged_variant(
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.deserialize_with() {
|
||||
let (wrapper, wrapper_ty, unwrap_fn) =
|
||||
wrap_deserialize_variant_with(params, &variant, path);
|
||||
wrap_deserialize_variant_with(params, variant, path);
|
||||
return quote_block! {
|
||||
#wrapper
|
||||
_serde::export::Result::map(
|
||||
@@ -1599,7 +1610,7 @@ fn deserialize_untagged_variant(
|
||||
variant_ident,
|
||||
params,
|
||||
&variant.fields[0],
|
||||
deserializer,
|
||||
&deserializer,
|
||||
),
|
||||
Style::Tuple => deserialize_tuple(
|
||||
Some(variant_ident),
|
||||
@@ -1614,7 +1625,7 @@ fn deserialize_untagged_variant(
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
Some(deserializer),
|
||||
Untagged::Yes,
|
||||
&Untagged::Yes,
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -1650,7 +1661,7 @@ fn deserialize_untagged_newtype_variant(
|
||||
variant_ident: &syn::Ident,
|
||||
params: &Parameters,
|
||||
field: &Field,
|
||||
deserializer: Tokens,
|
||||
deserializer: &Tokens,
|
||||
) -> Fragment {
|
||||
let this = ¶ms.this;
|
||||
match field.attrs.deserialize_with() {
|
||||
@@ -1675,7 +1686,7 @@ fn deserialize_untagged_newtype_variant(
|
||||
}
|
||||
|
||||
fn deserialize_generated_identifier(
|
||||
fields: Vec<(String, Ident)>,
|
||||
fields: &[(String, Ident)],
|
||||
cattrs: &attr::Container,
|
||||
is_variant: bool,
|
||||
) -> Fragment {
|
||||
@@ -1691,8 +1702,8 @@ fn deserialize_generated_identifier(
|
||||
};
|
||||
|
||||
let visitor_impl = Stmts(deserialize_identifier(
|
||||
this,
|
||||
&fields,
|
||||
&this,
|
||||
fields,
|
||||
is_variant,
|
||||
fallthrough,
|
||||
));
|
||||
@@ -1764,7 +1775,7 @@ fn deserialize_custom_identifier(
|
||||
.map(|variant| {
|
||||
(
|
||||
variant.attrs.name().deserialize_name(),
|
||||
variant.ident.clone(),
|
||||
variant.ident,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
@@ -1789,7 +1800,7 @@ fn deserialize_custom_identifier(
|
||||
split_with_de_lifetime(params);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
let visitor_impl = Stmts(deserialize_identifier(
|
||||
this.clone(),
|
||||
&this,
|
||||
&names_idents,
|
||||
is_variant,
|
||||
fallthrough,
|
||||
@@ -1818,13 +1829,13 @@ fn deserialize_custom_identifier(
|
||||
}
|
||||
|
||||
fn deserialize_identifier(
|
||||
this: Tokens,
|
||||
this: &Tokens,
|
||||
fields: &[(String, Ident)],
|
||||
is_variant: bool,
|
||||
fallthrough: Option<Tokens>,
|
||||
) -> Fragment {
|
||||
let field_strs = fields.iter().map(|&(ref name, _)| name);
|
||||
let field_bytes = fields.iter().map(|&(ref name, _)| quote::ByteStr(name));
|
||||
let field_bytes = fields.iter().map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
|
||||
|
||||
let constructors: &Vec<_> = &fields
|
||||
.iter()
|
||||
@@ -1912,7 +1923,7 @@ fn deserialize_identifier(
|
||||
}
|
||||
|
||||
fn deserialize_struct_visitor(
|
||||
struct_path: Tokens,
|
||||
struct_path: &Tokens,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
@@ -1931,7 +1942,7 @@ fn deserialize_struct_visitor(
|
||||
}
|
||||
};
|
||||
|
||||
let field_visitor = deserialize_generated_identifier(field_names_idents, cattrs, false);
|
||||
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false);
|
||||
|
||||
let visit_map = deserialize_map(struct_path, params, fields, cattrs);
|
||||
|
||||
@@ -1939,7 +1950,7 @@ fn deserialize_struct_visitor(
|
||||
}
|
||||
|
||||
fn deserialize_map(
|
||||
struct_path: Tokens,
|
||||
struct_path: &Tokens,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
@@ -1972,8 +1983,10 @@ fn deserialize_map(
|
||||
let visit = match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
let field_ty = &field.ty;
|
||||
let span = Span::def_site().located_at(field.original.span());
|
||||
let func = quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>);
|
||||
quote! {
|
||||
try!(_serde::de::MapAccess::next_value::<#field_ty>(&mut __map))
|
||||
try!(#func(&mut __map))
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
@@ -2027,7 +2040,7 @@ fn deserialize_map(
|
||||
.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
||||
.map(|&(field, ref name)| {
|
||||
let missing_expr = Match(expr_is_missing(&field, cattrs));
|
||||
let missing_expr = Match(expr_is_missing(field, cattrs));
|
||||
|
||||
quote! {
|
||||
let #name = match #name {
|
||||
@@ -2038,12 +2051,12 @@ fn deserialize_map(
|
||||
});
|
||||
|
||||
let result = fields_names.iter().map(|&(field, ref name)| {
|
||||
let ident = field.ident.clone().expect("struct contains unnamed fields");
|
||||
let ident = field.ident.expect("struct contains unnamed fields");
|
||||
if field.attrs.skip_deserializing() {
|
||||
let value = Expr(expr_is_missing(&field, cattrs));
|
||||
quote!(#ident: #value)
|
||||
let value = Expr(expr_is_missing(field, cattrs));
|
||||
quote_spanned!(Span::call_site()=> #ident: #value)
|
||||
} else {
|
||||
quote!(#ident: #name)
|
||||
quote_spanned!(Span::call_site()=> #ident: #name)
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2061,7 +2074,7 @@ fn deserialize_map(
|
||||
}
|
||||
};
|
||||
|
||||
let mut result = quote!(#struct_path { #(#result),* });
|
||||
let mut result = quote_spanned!(Span::call_site()=> #struct_path { #(#result),* });
|
||||
if params.has_getter {
|
||||
let this = ¶ms.this;
|
||||
result = quote! {
|
||||
@@ -2102,7 +2115,7 @@ fn deserialize_struct_in_place_visitor(
|
||||
}
|
||||
};
|
||||
|
||||
let field_visitor = deserialize_generated_identifier(field_names_idents, cattrs, false);
|
||||
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false);
|
||||
|
||||
let visit_map = deserialize_map_in_place(params, fields, cattrs);
|
||||
|
||||
@@ -2199,11 +2212,11 @@ fn deserialize_map_in_place(
|
||||
.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
||||
.map(|&(field, ref name)| {
|
||||
let missing_expr = expr_is_missing(&field, cattrs);
|
||||
let missing_expr = expr_is_missing(field, cattrs);
|
||||
// If missing_expr unconditionally returns an error, don't try
|
||||
// to assign its value to self.place. Maybe this could be handled
|
||||
// more elegantly.
|
||||
if missing_expr.as_ref().as_str().starts_with("return ") {
|
||||
if missing_expr.as_ref().into_tokens().to_string().starts_with("return ") {
|
||||
let missing_expr = Stmts(missing_expr);
|
||||
quote! {
|
||||
if !#name {
|
||||
@@ -2252,14 +2265,14 @@ fn deserialize_map_in_place(
|
||||
}
|
||||
|
||||
fn field_i(i: usize) -> Ident {
|
||||
Ident::new(format!("__field{}", i))
|
||||
Ident::new(&format!("__field{}", i), Span::def_site())
|
||||
}
|
||||
|
||||
/// This function wraps the expression in `#[serde(deserialize_with = "...")]`
|
||||
/// in a trait to prevent it from accessing the internal `Deserialize` state.
|
||||
fn wrap_deserialize_with(
|
||||
params: &Parameters,
|
||||
value_ty: Tokens,
|
||||
value_ty: &Tokens,
|
||||
deserialize_with: &syn::Path,
|
||||
) -> (Tokens, Tokens) {
|
||||
let this = ¶ms.this;
|
||||
@@ -2294,10 +2307,10 @@ fn wrap_deserialize_with(
|
||||
|
||||
fn wrap_deserialize_field_with(
|
||||
params: &Parameters,
|
||||
field_ty: &syn::Ty,
|
||||
field_ty: &syn::Type,
|
||||
deserialize_with: &syn::Path,
|
||||
) -> (Tokens, Tokens) {
|
||||
wrap_deserialize_with(params, quote!(#field_ty), deserialize_with)
|
||||
wrap_deserialize_with(params, "e!(#field_ty), deserialize_with)
|
||||
}
|
||||
|
||||
fn wrap_deserialize_variant_with(
|
||||
@@ -2310,9 +2323,12 @@ fn wrap_deserialize_variant_with(
|
||||
|
||||
let field_tys = variant.fields.iter().map(|field| field.ty);
|
||||
let (wrapper, wrapper_ty) =
|
||||
wrap_deserialize_with(params, quote!((#(#field_tys),*)), deserialize_with);
|
||||
wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with);
|
||||
|
||||
let field_access = (0..variant.fields.len()).map(|n| Ident::new(format!("{}", n)));
|
||||
let field_access = (0..variant.fields.len()).map(|n| Member::Unnamed(Index {
|
||||
index: n as u32,
|
||||
span: Span::call_site(),
|
||||
}));
|
||||
let unwrap_fn = match variant.style {
|
||||
Style::Struct => {
|
||||
let field_idents = variant
|
||||
@@ -2365,8 +2381,10 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
|
||||
let name = field.attrs.name().deserialize_name();
|
||||
match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
let span = Span::def_site().located_at(field.original.span());
|
||||
let func = quote_spanned!(span=> _serde::private::de::missing_field);
|
||||
quote_expr! {
|
||||
try!(_serde::private::de::missing_field(#name))
|
||||
try!(#func(#name))
|
||||
}
|
||||
}
|
||||
Some(_) => {
|
||||
@@ -2385,7 +2403,10 @@ impl<'a> ToTokens for DeImplGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
let mut generics = self.0.generics.clone();
|
||||
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
|
||||
generics.lifetimes.insert(0, de_lifetime);
|
||||
generics.params = Some(syn::GenericParam::Lifetime(de_lifetime))
|
||||
.into_iter()
|
||||
.chain(generics.params)
|
||||
.collect();
|
||||
}
|
||||
let (impl_generics, _, _) = generics.split_for_impl();
|
||||
impl_generics.to_tokens(tokens);
|
||||
@@ -2399,17 +2420,27 @@ impl<'a> ToTokens for InPlaceImplGenerics<'a> {
|
||||
let mut generics = self.0.generics.clone();
|
||||
|
||||
// Add lifetime for `&'place mut Self, and `'a: 'place`
|
||||
for lifetime in &mut generics.lifetimes {
|
||||
lifetime.bounds.push(place_lifetime.lifetime.clone());
|
||||
for param in &mut generics.params {
|
||||
match *param {
|
||||
syn::GenericParam::Lifetime(ref mut param) => {
|
||||
param.bounds.push(place_lifetime.lifetime);
|
||||
}
|
||||
syn::GenericParam::Type(ref mut param) => {
|
||||
param.bounds
|
||||
.push(syn::TypeParamBound::Lifetime(place_lifetime.lifetime));
|
||||
}
|
||||
syn::GenericParam::Const(_) => {}
|
||||
}
|
||||
}
|
||||
for generic in &mut generics.ty_params {
|
||||
generic
|
||||
.bounds
|
||||
.push(syn::TyParamBound::Region(place_lifetime.lifetime.clone()));
|
||||
}
|
||||
generics.lifetimes.insert(0, place_lifetime);
|
||||
generics.params = Some(syn::GenericParam::Lifetime(place_lifetime))
|
||||
.into_iter()
|
||||
.chain(generics.params)
|
||||
.collect();
|
||||
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
|
||||
generics.lifetimes.insert(0, de_lifetime);
|
||||
generics.params = Some(syn::GenericParam::Lifetime(de_lifetime))
|
||||
.into_iter()
|
||||
.chain(generics.params)
|
||||
.collect();
|
||||
}
|
||||
let (impl_generics, _, _) = generics.split_for_impl();
|
||||
impl_generics.to_tokens(tokens);
|
||||
@@ -2423,15 +2454,24 @@ impl<'a> DeImplGenerics<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
struct DeTyGenerics<'a>(&'a Parameters);
|
||||
struct DeTypeGenerics<'a>(&'a Parameters);
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
struct InPlaceTyGenerics<'a>(&'a Parameters);
|
||||
struct InPlaceTypeGenerics<'a>(&'a Parameters);
|
||||
|
||||
impl<'a> ToTokens for DeTyGenerics<'a> {
|
||||
impl<'a> ToTokens for DeTypeGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
let mut generics = self.0.generics.clone();
|
||||
if self.0.borrowed.de_lifetime_def().is_some() {
|
||||
generics.lifetimes.insert(0, syn::LifetimeDef::new("'de"));
|
||||
let def = syn::LifetimeDef {
|
||||
attrs: Vec::new(),
|
||||
lifetime: syn::Lifetime::new(Term::intern("'de"), Span::def_site()),
|
||||
colon_token: None,
|
||||
bounds: Punctuated::new(),
|
||||
};
|
||||
generics.params = Some(syn::GenericParam::Lifetime(def))
|
||||
.into_iter()
|
||||
.chain(generics.params)
|
||||
.collect();
|
||||
}
|
||||
let (_, ty_generics, _) = generics.split_for_impl();
|
||||
ty_generics.to_tokens(tokens);
|
||||
@@ -2439,13 +2479,25 @@ impl<'a> ToTokens for DeTyGenerics<'a> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
impl<'a> ToTokens for InPlaceTyGenerics<'a> {
|
||||
impl<'a> ToTokens for InPlaceTypeGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
let mut generics = self.0.generics.clone();
|
||||
generics.lifetimes.insert(0, place_lifetime());
|
||||
generics.params = Some(syn::GenericParam::Lifetime(place_lifetime()))
|
||||
.into_iter()
|
||||
.chain(generics.params)
|
||||
.collect();
|
||||
|
||||
if self.0.borrowed.de_lifetime_def().is_some() {
|
||||
generics.lifetimes.insert(0, syn::LifetimeDef::new("'de"));
|
||||
let def = syn::LifetimeDef {
|
||||
attrs: Vec::new(),
|
||||
lifetime: syn::Lifetime::new(Term::intern("'de"), Span::def_site()),
|
||||
colon_token: None,
|
||||
bounds: Punctuated::new(),
|
||||
};
|
||||
generics.params = Some(syn::GenericParam::Lifetime(def))
|
||||
.into_iter()
|
||||
.chain(generics.params)
|
||||
.collect();
|
||||
}
|
||||
let (_, ty_generics, _) = generics.split_for_impl();
|
||||
ty_generics.to_tokens(tokens);
|
||||
@@ -2453,27 +2505,32 @@ impl<'a> ToTokens for InPlaceTyGenerics<'a> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
impl<'a> DeTyGenerics<'a> {
|
||||
fn in_place(self) -> InPlaceTyGenerics<'a> {
|
||||
InPlaceTyGenerics(self.0)
|
||||
impl<'a> DeTypeGenerics<'a> {
|
||||
fn in_place(self) -> InPlaceTypeGenerics<'a> {
|
||||
InPlaceTypeGenerics(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
fn place_lifetime() -> syn::LifetimeDef {
|
||||
syn::LifetimeDef::new("'place")
|
||||
syn::LifetimeDef {
|
||||
attrs: Vec::new(),
|
||||
lifetime: syn::Lifetime::new(Term::intern("'place"), Span::def_site()),
|
||||
colon_token: None,
|
||||
bounds: Punctuated::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn split_with_de_lifetime(
|
||||
params: &Parameters,
|
||||
) -> (
|
||||
DeImplGenerics,
|
||||
DeTyGenerics,
|
||||
syn::TyGenerics,
|
||||
&syn::WhereClause,
|
||||
DeTypeGenerics,
|
||||
syn::TypeGenerics,
|
||||
Option<&syn::WhereClause>,
|
||||
) {
|
||||
let de_impl_generics = DeImplGenerics(¶ms);
|
||||
let de_ty_generics = DeTyGenerics(¶ms);
|
||||
let de_impl_generics = DeImplGenerics(params);
|
||||
let de_ty_generics = DeTypeGenerics(params);
|
||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
(de_impl_generics, de_ty_generics, ty_generics, where_clause)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use quote::{ToTokens, Tokens};
|
||||
use syn::token;
|
||||
|
||||
pub enum Fragment {
|
||||
/// Tokens that can be used as an expression.
|
||||
@@ -36,9 +37,7 @@ impl ToTokens for Expr {
|
||||
match self.0 {
|
||||
Fragment::Expr(ref expr) => expr.to_tokens(out),
|
||||
Fragment::Block(ref block) => {
|
||||
out.append("{");
|
||||
block.to_tokens(out);
|
||||
out.append("}");
|
||||
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,12 +62,10 @@ impl ToTokens for Match {
|
||||
match self.0 {
|
||||
Fragment::Expr(ref expr) => {
|
||||
expr.to_tokens(out);
|
||||
out.append(",");
|
||||
<Token![,]>::default().to_tokens(out);
|
||||
}
|
||||
Fragment::Block(ref block) => {
|
||||
out.append("{");
|
||||
block.to_tokens(out);
|
||||
out.append("}");
|
||||
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-8
@@ -22,20 +22,24 @@
|
||||
//!
|
||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.25")]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.30")]
|
||||
#![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 = "192"]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
extern crate serde_derive_internals as internals;
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate proc_macro2;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::DeriveInput;
|
||||
|
||||
#[macro_use]
|
||||
mod bound;
|
||||
@@ -47,18 +51,18 @@ mod de;
|
||||
|
||||
#[proc_macro_derive(Serialize, attributes(serde))]
|
||||
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_derive_input(&input.to_string()).unwrap();
|
||||
let input: DeriveInput = syn::parse(input).unwrap();
|
||||
match ser::expand_derive_serialize(&input) {
|
||||
Ok(expanded) => expanded.parse().unwrap(),
|
||||
Ok(expanded) => expanded.into(),
|
||||
Err(msg) => panic!(msg),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Deserialize, attributes(serde))]
|
||||
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_derive_input(&input.to_string()).unwrap();
|
||||
let input: DeriveInput = syn::parse(input).unwrap();
|
||||
match de::expand_derive_deserialize(&input) {
|
||||
Ok(expanded) => expanded.parse().unwrap(),
|
||||
Ok(expanded) => expanded.into(),
|
||||
Err(msg) => panic!(msg),
|
||||
}
|
||||
}
|
||||
|
||||
+140
-81
@@ -6,12 +6,14 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use syn::{self, Ident};
|
||||
use syn::{self, Ident, Index, Member};
|
||||
use syn::spanned::Spanned;
|
||||
use quote::Tokens;
|
||||
use proc_macro2::Span;
|
||||
|
||||
use bound;
|
||||
use fragment::{Fragment, Match, Stmts};
|
||||
use internals::ast::{Body, Container, Field, Style, Variant};
|
||||
use internals::ast::{Data, Container, Field, Style, Variant};
|
||||
use internals::{attr, Ctxt};
|
||||
|
||||
use std::u32;
|
||||
@@ -25,14 +27,15 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, Strin
|
||||
let ident = &cont.ident;
|
||||
let params = Parameters::new(&cont);
|
||||
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
let dummy_const = Ident::new(format!("_IMPL_SERIALIZE_FOR_{}", ident));
|
||||
let dummy_const = Ident::new(&format!("_IMPL_SERIALIZE_FOR_{}", ident), Span::def_site());
|
||||
let body = Stmts(serialize_body(&cont, ¶ms));
|
||||
|
||||
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||
let vis = &input.vis;
|
||||
let fun = quote_spanned!(Span::call_site()=> serialize);
|
||||
quote! {
|
||||
impl #impl_generics #ident #ty_generics #where_clause {
|
||||
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
#vis fn #fun<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
where __S: _serde::Serializer
|
||||
{
|
||||
#body
|
||||
@@ -95,14 +98,14 @@ impl Parameters {
|
||||
fn new(cont: &Container) -> Self {
|
||||
let is_remote = cont.attrs.remote().is_some();
|
||||
let self_var = if is_remote {
|
||||
Ident::new("__self")
|
||||
Ident::new("__self", Span::def_site())
|
||||
} else {
|
||||
Ident::new("self")
|
||||
Ident::new("self", Span::def_site())
|
||||
};
|
||||
|
||||
let this = match cont.attrs.remote() {
|
||||
Some(remote) => remote.clone(),
|
||||
None => cont.ident.clone().into(),
|
||||
None => cont.ident.into(),
|
||||
};
|
||||
|
||||
let generics = build_generics(cont);
|
||||
@@ -118,7 +121,7 @@ impl Parameters {
|
||||
/// Type name to use in error messages and `&'static str` arguments to
|
||||
/// various Serializer methods.
|
||||
fn type_name(&self) -> &str {
|
||||
self.this.segments.last().unwrap().ident.as_ref()
|
||||
self.this.segments.last().unwrap().value().ident.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +139,7 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
||||
cont,
|
||||
&generics,
|
||||
needs_serialize_bound,
|
||||
&path!(_serde::Serialize),
|
||||
&parse_quote!(_serde::Serialize),
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -152,36 +155,36 @@ fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -
|
||||
}
|
||||
|
||||
fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||
if let Some(into_type) = cont.attrs.into_type() {
|
||||
serialize_into(params, into_type)
|
||||
if let Some(type_into) = cont.attrs.type_into() {
|
||||
serialize_into(params, type_into)
|
||||
} else {
|
||||
match cont.body {
|
||||
Body::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
|
||||
Body::Struct(Style::Struct, ref fields) => {
|
||||
match cont.data {
|
||||
Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
|
||||
Data::Struct(Style::Struct, ref fields) => {
|
||||
if fields.iter().any(|field| field.ident.is_none()) {
|
||||
panic!("struct has unnamed fields");
|
||||
}
|
||||
serialize_struct(params, fields, &cont.attrs)
|
||||
}
|
||||
Body::Struct(Style::Tuple, ref fields) => {
|
||||
Data::Struct(Style::Tuple, ref fields) => {
|
||||
if fields.iter().any(|field| field.ident.is_some()) {
|
||||
panic!("tuple struct has named fields");
|
||||
}
|
||||
serialize_tuple_struct(params, fields, &cont.attrs)
|
||||
}
|
||||
Body::Struct(Style::Newtype, ref fields) => {
|
||||
Data::Struct(Style::Newtype, ref fields) => {
|
||||
serialize_newtype_struct(params, &fields[0], &cont.attrs)
|
||||
}
|
||||
Body::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs),
|
||||
Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_into(params: &Parameters, into_type: &syn::Ty) -> Fragment {
|
||||
fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment {
|
||||
let self_var = ¶ms.self_var;
|
||||
quote_block! {
|
||||
_serde::Serialize::serialize(
|
||||
&_serde::export::Into::<#into_type>::into(_serde::export::Clone::clone(#self_var)),
|
||||
&_serde::export::Into::<#type_into>::into(_serde::export::Clone::clone(#self_var)),
|
||||
__serializer)
|
||||
}
|
||||
}
|
||||
@@ -201,13 +204,18 @@ fn serialize_newtype_struct(
|
||||
) -> Fragment {
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
|
||||
let mut field_expr = get_field(params, field, 0);
|
||||
let mut field_expr = get_member(params, field, &Member::Unnamed(Index {
|
||||
index: 0,
|
||||
span: Span::call_site(),
|
||||
}));
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
let span = Span::def_site().located_at(field.original.span());
|
||||
let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_struct);
|
||||
quote_expr! {
|
||||
_serde::Serializer::serialize_newtype_struct(__serializer, #type_name, #field_expr)
|
||||
#func(__serializer, #type_name, #field_expr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +228,7 @@ fn serialize_tuple_struct(
|
||||
fields,
|
||||
params,
|
||||
false,
|
||||
quote!(_serde::ser::SerializeTupleStruct::serialize_field),
|
||||
&TupleTrait::SerializeTupleStruct,
|
||||
);
|
||||
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
@@ -235,14 +243,13 @@ fn serialize_tuple_struct(
|
||||
}
|
||||
|
||||
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
||||
assert!(fields.len() as u64 <= u32::MAX as u64);
|
||||
assert!(fields.len() as u64 <= u64::from(u32::MAX));
|
||||
|
||||
let serialize_fields = serialize_struct_visitor(
|
||||
fields,
|
||||
params,
|
||||
false,
|
||||
quote!(_serde::ser::SerializeStruct::serialize_field),
|
||||
quote!(_serde::ser::SerializeStruct::skip_field),
|
||||
&StructTrait::SerializeStruct,
|
||||
);
|
||||
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
@@ -258,8 +265,8 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
|
||||
.map(|field| match field.attrs.skip_serializing_if() {
|
||||
None => quote!(1),
|
||||
Some(path) => {
|
||||
let ident = field.ident.clone().expect("struct has unnamed fields");
|
||||
let field_expr = get_field(params, field, ident);
|
||||
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 })
|
||||
}
|
||||
})
|
||||
@@ -273,7 +280,7 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
|
||||
}
|
||||
|
||||
fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment {
|
||||
assert!(variants.len() as u64 <= u32::MAX as u64);
|
||||
assert!(variants.len() as u64 <= u64::from(u32::MAX));
|
||||
|
||||
let self_var = ¶ms.self_var;
|
||||
|
||||
@@ -299,7 +306,7 @@ fn serialize_variant(
|
||||
cattrs: &attr::Container,
|
||||
) -> Tokens {
|
||||
let this = ¶ms.this;
|
||||
let variant_ident = variant.ident.clone();
|
||||
let variant_ident = variant.ident;
|
||||
|
||||
if variant.attrs.skip_serializing() {
|
||||
let skipped_msg = format!(
|
||||
@@ -333,7 +340,7 @@ fn serialize_variant(
|
||||
}
|
||||
Style::Tuple => {
|
||||
let field_names =
|
||||
(0..variant.fields.len()).map(|i| Ident::new(format!("__field{}", i)));
|
||||
(0..variant.fields.len()).map(|i| Ident::new(&format!("__field{}", i), Span::def_site()));
|
||||
quote! {
|
||||
#this::#variant_ident(#(ref #field_names),*)
|
||||
}
|
||||
@@ -342,7 +349,7 @@ fn serialize_variant(
|
||||
let fields = variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| f.ident.clone().expect("struct variant has unnamed fields"));
|
||||
.map(|f| f.ident.expect("struct variant has unnamed fields"));
|
||||
quote! {
|
||||
#this::#variant_ident { #(ref #fields),* }
|
||||
}
|
||||
@@ -379,7 +386,7 @@ fn serialize_externally_tagged_variant(
|
||||
let variant_name = variant.attrs.name().serialize_name();
|
||||
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
let ser = wrap_serialize_variant_with(params, path, variant);
|
||||
return quote_expr! {
|
||||
_serde::Serializer::serialize_newtype_variant(
|
||||
__serializer,
|
||||
@@ -406,7 +413,7 @@ fn serialize_externally_tagged_variant(
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -453,7 +460,7 @@ fn serialize_internally_tagged_variant(
|
||||
let variant_ident_str = variant.ident.as_ref();
|
||||
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
let ser = wrap_serialize_variant_with(params, path, variant);
|
||||
return quote_expr! {
|
||||
_serde::private::ser::serialize_tagged_newtype(
|
||||
__serializer,
|
||||
@@ -480,7 +487,7 @@ fn serialize_internally_tagged_variant(
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -519,7 +526,7 @@ fn serialize_adjacently_tagged_variant(
|
||||
let variant_name = variant.attrs.name().serialize_name();
|
||||
|
||||
let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
let ser = wrap_serialize_variant_with(params, path, variant);
|
||||
quote_expr! {
|
||||
_serde::Serialize::serialize(#ser, __serializer)
|
||||
}
|
||||
@@ -538,7 +545,7 @@ fn serialize_adjacently_tagged_variant(
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -558,7 +565,7 @@ fn serialize_adjacently_tagged_variant(
|
||||
});
|
||||
|
||||
let fields_ty = variant.fields.iter().map(|f| &f.ty);
|
||||
let ref fields_ident: Vec<_> = match variant.style {
|
||||
let fields_ident: &Vec<_> = &match variant.style {
|
||||
Style::Unit => {
|
||||
if variant.attrs.serialize_with().is_some() {
|
||||
vec![]
|
||||
@@ -566,14 +573,14 @@ fn serialize_adjacently_tagged_variant(
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
Style::Newtype => vec![Ident::new("__field0")],
|
||||
Style::Newtype => vec![Ident::new("__field0", Span::def_site())],
|
||||
Style::Tuple => (0..variant.fields.len())
|
||||
.map(|i| Ident::new(format!("__field{}", i)))
|
||||
.map(|i| Ident::new(&format!("__field{}", i), Span::def_site()))
|
||||
.collect(),
|
||||
Style::Struct => variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| f.ident.clone().expect("struct variant has unnamed fields"))
|
||||
.map(|f| f.ident.expect("struct variant has unnamed fields"))
|
||||
.collect(),
|
||||
};
|
||||
|
||||
@@ -620,7 +627,7 @@ fn serialize_untagged_variant(
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
let ser = wrap_serialize_variant_with(params, path, variant);
|
||||
return quote_expr! {
|
||||
_serde::Serialize::serialize(#ser, __serializer)
|
||||
};
|
||||
@@ -636,7 +643,7 @@ fn serialize_untagged_variant(
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -665,14 +672,12 @@ fn serialize_tuple_variant(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
) -> Fragment {
|
||||
let method = match context {
|
||||
TupleVariant::ExternallyTagged { .. } => {
|
||||
quote!(_serde::ser::SerializeTupleVariant::serialize_field)
|
||||
}
|
||||
TupleVariant::Untagged => quote!(_serde::ser::SerializeTuple::serialize_element),
|
||||
let tuple_trait = match context {
|
||||
TupleVariant::ExternallyTagged { .. } => TupleTrait::SerializeTupleVariant,
|
||||
TupleVariant::Untagged => TupleTrait::SerializeTuple,
|
||||
};
|
||||
|
||||
let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, method);
|
||||
let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, &tuple_trait);
|
||||
|
||||
let len = serialize_stmts.len();
|
||||
let let_mut = mut_if(len > 0);
|
||||
@@ -724,18 +729,16 @@ fn serialize_struct_variant<'a>(
|
||||
fields: &[Field],
|
||||
name: &str,
|
||||
) -> Fragment {
|
||||
let (method, skip_method) = match context {
|
||||
let struct_trait = match context {
|
||||
StructVariant::ExternallyTagged { .. } => (
|
||||
quote!(_serde::ser::SerializeStructVariant::serialize_field),
|
||||
quote!(_serde::ser::SerializeStructVariant::skip_field),
|
||||
StructTrait::SerializeStructVariant
|
||||
),
|
||||
StructVariant::InternallyTagged { .. } | StructVariant::Untagged => (
|
||||
quote!(_serde::ser::SerializeStruct::serialize_field),
|
||||
quote!(_serde::ser::SerializeStruct::skip_field),
|
||||
StructTrait::SerializeStruct
|
||||
),
|
||||
};
|
||||
|
||||
let serialize_fields = serialize_struct_visitor(fields, params, true, method, skip_method);
|
||||
let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait);
|
||||
|
||||
let mut serialized_fields = fields
|
||||
.iter()
|
||||
@@ -746,7 +749,7 @@ fn serialize_struct_variant<'a>(
|
||||
|
||||
let len = serialized_fields
|
||||
.map(|field| {
|
||||
let ident = field.ident.clone().expect("struct has unnamed fields");
|
||||
let ident = field.ident.expect("struct has unnamed fields");
|
||||
|
||||
match field.attrs.skip_serializing_if() {
|
||||
Some(path) => quote!(if #path(#ident) { 0 } else { 1 }),
|
||||
@@ -806,17 +809,20 @@ fn serialize_tuple_struct_visitor(
|
||||
fields: &[Field],
|
||||
params: &Parameters,
|
||||
is_enum: bool,
|
||||
func: Tokens,
|
||||
tuple_trait: &TupleTrait,
|
||||
) -> Vec<Tokens> {
|
||||
fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
let mut field_expr = if is_enum {
|
||||
let id = Ident::new(format!("__field{}", i));
|
||||
let id = Ident::new(&format!("__field{}", i), Span::def_site());
|
||||
quote!(#id)
|
||||
} else {
|
||||
get_field(params, field, i)
|
||||
get_member(params, field, &Member::Unnamed(Index {
|
||||
index: i as u32,
|
||||
span: Span::call_site(),
|
||||
}))
|
||||
};
|
||||
|
||||
let skip = field
|
||||
@@ -825,9 +831,11 @@ fn serialize_tuple_struct_visitor(
|
||||
.map(|path| quote!(#path(#field_expr)));
|
||||
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
let span = Span::def_site().located_at(field.original.span());
|
||||
let func = tuple_trait.serialize_element(span);
|
||||
let ser = quote! {
|
||||
try!(#func(&mut __serde_state, #field_expr));
|
||||
};
|
||||
@@ -844,18 +852,17 @@ fn serialize_struct_visitor(
|
||||
fields: &[Field],
|
||||
params: &Parameters,
|
||||
is_enum: bool,
|
||||
func: Tokens,
|
||||
skip_func: Tokens,
|
||||
struct_trait: &StructTrait,
|
||||
) -> Vec<Tokens> {
|
||||
fields
|
||||
.iter()
|
||||
.filter(|&field| !field.attrs.skip_serializing())
|
||||
.map(|field| {
|
||||
let field_ident = field.ident.clone().expect("struct has unnamed field");
|
||||
let field_ident = field.ident.expect("struct has unnamed field");
|
||||
let mut field_expr = if is_enum {
|
||||
quote!(#field_ident)
|
||||
} else {
|
||||
get_field(params, field, field_ident)
|
||||
get_member(params, field, &Member::Named(field_ident))
|
||||
};
|
||||
|
||||
let key_expr = field.attrs.name().serialize_name();
|
||||
@@ -866,9 +873,11 @@ fn serialize_struct_visitor(
|
||||
.map(|path| quote!(#path(#field_expr)));
|
||||
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
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));
|
||||
};
|
||||
@@ -876,6 +885,7 @@ fn serialize_struct_visitor(
|
||||
match skip {
|
||||
None => ser,
|
||||
Some(skip) => {
|
||||
let skip_func = struct_trait.skip_field(span);
|
||||
quote! {
|
||||
if !#skip {
|
||||
#ser
|
||||
@@ -891,9 +901,9 @@ fn serialize_struct_visitor(
|
||||
|
||||
fn wrap_serialize_field_with(
|
||||
params: &Parameters,
|
||||
field_ty: &syn::Ty,
|
||||
field_ty: &syn::Type,
|
||||
serialize_with: &syn::Path,
|
||||
field_expr: Tokens,
|
||||
field_expr: &Tokens,
|
||||
) -> Tokens {
|
||||
wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)])
|
||||
}
|
||||
@@ -911,8 +921,7 @@ fn wrap_serialize_variant_with(
|
||||
.map(|(i, field)| {
|
||||
let id = field
|
||||
.ident
|
||||
.as_ref()
|
||||
.map_or_else(|| Ident::new(format!("__field{}", i)), |id| id.clone());
|
||||
.unwrap_or_else(|| Ident::new(&format!("__field{}", i), Span::def_site()));
|
||||
quote!(#id)
|
||||
})
|
||||
.collect();
|
||||
@@ -927,20 +936,23 @@ fn wrap_serialize_variant_with(
|
||||
fn wrap_serialize_with(
|
||||
params: &Parameters,
|
||||
serialize_with: &syn::Path,
|
||||
field_tys: &[&syn::Ty],
|
||||
field_tys: &[&syn::Type],
|
||||
field_exprs: &[Tokens],
|
||||
) -> Tokens {
|
||||
let this = ¶ms.this;
|
||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
|
||||
let wrapper_generics = if field_exprs.len() == 0 {
|
||||
let wrapper_generics = if field_exprs.is_empty() {
|
||||
params.generics.clone()
|
||||
} else {
|
||||
bound::with_lifetime_bound(¶ms.generics, "'__a")
|
||||
};
|
||||
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
||||
|
||||
let field_access = (0..field_exprs.len()).map(|n| Ident::new(format!("{}", n)));
|
||||
let field_access = (0..field_exprs.len()).map(|n| Member::Unnamed(Index {
|
||||
index: n as u32,
|
||||
span: Span::call_site(),
|
||||
}));
|
||||
|
||||
quote!({
|
||||
struct __SerializeWith #wrapper_impl_generics #where_clause {
|
||||
@@ -977,20 +989,16 @@ fn mut_if(is_mut: bool) -> Option<Tokens> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_field<I>(params: &Parameters, field: &Field, ident: I) -> Tokens
|
||||
where
|
||||
I: Into<Ident>,
|
||||
{
|
||||
fn get_member(params: &Parameters, field: &Field, member: &Member) -> Tokens {
|
||||
let self_var = ¶ms.self_var;
|
||||
match (params.is_remote, field.attrs.getter()) {
|
||||
(false, None) => {
|
||||
let ident = ident.into();
|
||||
quote!(&#self_var.#ident)
|
||||
quote_spanned!(Span::call_site()=> &#self_var.#member)
|
||||
}
|
||||
(true, None) => {
|
||||
let inner = quote_spanned!(Span::call_site()=> &#self_var.#member);
|
||||
let ty = field.ty;
|
||||
let ident = ident.into();
|
||||
quote!(_serde::private::ser::constrain::<#ty>(&#self_var.#ident))
|
||||
quote!(_serde::private::ser::constrain::<#ty>(#inner))
|
||||
}
|
||||
(true, Some(getter)) => {
|
||||
let ty = field.ty;
|
||||
@@ -1001,3 +1009,54 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum StructTrait {
|
||||
SerializeStruct,
|
||||
SerializeStructVariant,
|
||||
}
|
||||
|
||||
impl StructTrait {
|
||||
fn serialize_field(&self, span: Span) -> Tokens {
|
||||
match *self {
|
||||
StructTrait::SerializeStruct => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field)
|
||||
}
|
||||
StructTrait::SerializeStructVariant => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeStructVariant::serialize_field)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn skip_field(&self, span: Span) -> Tokens {
|
||||
match *self {
|
||||
StructTrait::SerializeStruct => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)
|
||||
}
|
||||
StructTrait::SerializeStructVariant => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum TupleTrait {
|
||||
SerializeTuple,
|
||||
SerializeTupleStruct,
|
||||
SerializeTupleVariant,
|
||||
}
|
||||
|
||||
impl TupleTrait {
|
||||
fn serialize_element(&self, span: Span) -> Tokens {
|
||||
match *self {
|
||||
TupleTrait::SerializeTuple => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element)
|
||||
}
|
||||
TupleTrait::SerializeTupleStruct => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeTupleStruct::serialize_field)
|
||||
}
|
||||
TupleTrait::SerializeTupleVariant => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeTupleVariant::serialize_field)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.18.1" # remember to update html_root_url
|
||||
version = "0.20.0" # 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."
|
||||
@@ -12,8 +12,8 @@ readme = "README.md"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "0.11.10", default-features = false, features = ["parsing"] }
|
||||
synom = "0.11"
|
||||
proc-macro2 = "0.2"
|
||||
syn = { version = "0.12", default-features = false, features = ["derive", "parsing", "clone-impls"] }
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
|
||||
@@ -10,15 +10,16 @@ use syn;
|
||||
use attr;
|
||||
use check;
|
||||
use Ctxt;
|
||||
use syn::punctuated::Punctuated;
|
||||
|
||||
pub struct Container<'a> {
|
||||
pub ident: syn::Ident,
|
||||
pub attrs: attr::Container,
|
||||
pub body: Body<'a>,
|
||||
pub data: Data<'a>,
|
||||
pub generics: &'a syn::Generics,
|
||||
}
|
||||
|
||||
pub enum Body<'a> {
|
||||
pub enum Data<'a> {
|
||||
Enum(Vec<Variant<'a>>),
|
||||
Struct(Style, Vec<Field<'a>>),
|
||||
}
|
||||
@@ -33,7 +34,8 @@ pub struct Variant<'a> {
|
||||
pub struct Field<'a> {
|
||||
pub ident: Option<syn::Ident>,
|
||||
pub attrs: attr::Field,
|
||||
pub ty: &'a syn::Ty,
|
||||
pub ty: &'a syn::Type,
|
||||
pub original: &'a syn::Field,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@@ -48,32 +50,35 @@ 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 body = match item.body {
|
||||
syn::Body::Enum(ref variants) => {
|
||||
Body::Enum(enum_from_ast(cx, variants, &attrs.default()))
|
||||
let mut data = match item.data {
|
||||
syn::Data::Enum(ref data) => {
|
||||
Data::Enum(enum_from_ast(cx, &data.variants, attrs.default()))
|
||||
}
|
||||
syn::Body::Struct(ref variant_data) => {
|
||||
let (style, fields) = struct_from_ast(cx, variant_data, None, &attrs.default());
|
||||
Body::Struct(style, fields)
|
||||
syn::Data::Struct(ref data) => {
|
||||
let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default());
|
||||
Data::Struct(style, fields)
|
||||
}
|
||||
syn::Data::Union(_) => {
|
||||
panic!("Serde does not support derive for unions");
|
||||
}
|
||||
};
|
||||
|
||||
match body {
|
||||
Body::Enum(ref mut variants) => for ref mut variant in variants {
|
||||
match data {
|
||||
Data::Enum(ref mut variants) => for variant in variants {
|
||||
variant.attrs.rename_by_rule(attrs.rename_all());
|
||||
for ref mut field in &mut variant.fields {
|
||||
for field in &mut variant.fields {
|
||||
field.attrs.rename_by_rule(variant.attrs.rename_all());
|
||||
}
|
||||
},
|
||||
Body::Struct(_, ref mut fields) => for field in fields {
|
||||
Data::Struct(_, ref mut fields) => for field in fields {
|
||||
field.attrs.rename_by_rule(attrs.rename_all());
|
||||
},
|
||||
}
|
||||
|
||||
let item = Container {
|
||||
ident: item.ident.clone(),
|
||||
ident: item.ident,
|
||||
attrs: attrs,
|
||||
body: body,
|
||||
data: data,
|
||||
generics: &item.generics,
|
||||
};
|
||||
check::check(cx, &item);
|
||||
@@ -81,13 +86,13 @@ impl<'a> Container<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Body<'a> {
|
||||
impl<'a> Data<'a> {
|
||||
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
|
||||
match *self {
|
||||
Body::Enum(ref variants) => {
|
||||
Data::Enum(ref variants) => {
|
||||
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
|
||||
}
|
||||
Body::Struct(_, ref fields) => Box::new(fields.iter()),
|
||||
Data::Struct(_, ref fields) => Box::new(fields.iter()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +103,7 @@ impl<'a> Body<'a> {
|
||||
|
||||
fn enum_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
variants: &'a [syn::Variant],
|
||||
variants: &'a Punctuated<syn::Variant, Token![,]>,
|
||||
container_default: &attr::Default,
|
||||
) -> Vec<Variant<'a>> {
|
||||
variants
|
||||
@@ -106,9 +111,9 @@ fn enum_from_ast<'a>(
|
||||
.map(|variant| {
|
||||
let attrs = attr::Variant::from_ast(cx, variant);
|
||||
let (style, fields) =
|
||||
struct_from_ast(cx, &variant.data, Some(&attrs), container_default);
|
||||
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
|
||||
Variant {
|
||||
ident: variant.ident.clone(),
|
||||
ident: variant.ident,
|
||||
attrs: attrs,
|
||||
style: style,
|
||||
fields: fields,
|
||||
@@ -119,30 +124,30 @@ fn enum_from_ast<'a>(
|
||||
|
||||
fn struct_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
data: &'a syn::VariantData,
|
||||
fields: &'a syn::Fields,
|
||||
attrs: Option<&attr::Variant>,
|
||||
container_default: &attr::Default,
|
||||
) -> (Style, Vec<Field<'a>>) {
|
||||
match *data {
|
||||
syn::VariantData::Struct(ref fields) => (
|
||||
match *fields {
|
||||
syn::Fields::Named(ref fields) => (
|
||||
Style::Struct,
|
||||
fields_from_ast(cx, fields, attrs, container_default),
|
||||
fields_from_ast(cx, &fields.named, attrs, container_default),
|
||||
),
|
||||
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => (
|
||||
syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => (
|
||||
Style::Newtype,
|
||||
fields_from_ast(cx, fields, attrs, container_default),
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
|
||||
),
|
||||
syn::VariantData::Tuple(ref fields) => (
|
||||
syn::Fields::Unnamed(ref fields) => (
|
||||
Style::Tuple,
|
||||
fields_from_ast(cx, fields, attrs, container_default),
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
|
||||
),
|
||||
syn::VariantData::Unit => (Style::Unit, Vec::new()),
|
||||
syn::Fields::Unit => (Style::Unit, Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn fields_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
fields: &'a [syn::Field],
|
||||
fields: &'a Punctuated<syn::Field, Token![,]>,
|
||||
attrs: Option<&attr::Variant>,
|
||||
container_default: &attr::Default,
|
||||
) -> Vec<Field<'a>> {
|
||||
@@ -150,9 +155,10 @@ fn fields_from_ast<'a>(
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| Field {
|
||||
ident: field.ident.clone(),
|
||||
ident: field.ident,
|
||||
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
|
||||
ty: &field.ty,
|
||||
original: field,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
+351
-247
File diff suppressed because it is too large
Load Diff
@@ -14,12 +14,14 @@ use std::str::FromStr;
|
||||
|
||||
use self::RenameRule::*;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(PartialEq)]
|
||||
pub enum RenameRule {
|
||||
/// Don't apply a default rename rule.
|
||||
None,
|
||||
/// Rename direct children to "lowercase" style.
|
||||
LowerCase,
|
||||
/// Rename direct children to "UPPERCASE" style.
|
||||
UPPERCASE,
|
||||
/// Rename direct children to "PascalCase" style, as typically used for enum variants.
|
||||
PascalCase,
|
||||
/// Rename direct children to "camelCase" style.
|
||||
@@ -39,6 +41,7 @@ impl RenameRule {
|
||||
match *self {
|
||||
None | PascalCase => variant.to_owned(),
|
||||
LowerCase => variant.to_ascii_lowercase(),
|
||||
UPPERCASE => variant.to_ascii_uppercase(),
|
||||
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
|
||||
SnakeCase => {
|
||||
let mut snake = String::new();
|
||||
@@ -61,6 +64,7 @@ impl RenameRule {
|
||||
pub fn apply_to_field(&self, field: &str) -> String {
|
||||
match *self {
|
||||
None | LowerCase | SnakeCase => field.to_owned(),
|
||||
UPPERCASE => field.to_ascii_uppercase(),
|
||||
PascalCase => {
|
||||
let mut pascal = String::new();
|
||||
let mut capitalize = true;
|
||||
@@ -93,6 +97,7 @@ impl FromStr for RenameRule {
|
||||
fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
|
||||
match rename_all_str {
|
||||
"lowercase" => Ok(LowerCase),
|
||||
"UPPERCASE" => Ok(UPPERCASE),
|
||||
"PascalCase" => Ok(PascalCase),
|
||||
"camelCase" => Ok(CamelCase),
|
||||
"snake_case" => Ok(SnakeCase),
|
||||
@@ -106,10 +111,11 @@ impl FromStr for RenameRule {
|
||||
|
||||
#[test]
|
||||
fn rename_variants() {
|
||||
for &(original, lower, camel, snake, screaming, kebab, screaming_kebab) in &[
|
||||
for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
|
||||
(
|
||||
"Outcome",
|
||||
"outcome",
|
||||
"OUTCOME",
|
||||
"outcome",
|
||||
"outcome",
|
||||
"OUTCOME",
|
||||
@@ -119,17 +125,19 @@ fn rename_variants() {
|
||||
(
|
||||
"VeryTasty",
|
||||
"verytasty",
|
||||
"VERYTASTY",
|
||||
"veryTasty",
|
||||
"very_tasty",
|
||||
"VERY_TASTY",
|
||||
"very-tasty",
|
||||
"VERY-TASTY",
|
||||
),
|
||||
("A", "a", "a", "a", "A", "a", "A"),
|
||||
("Z42", "z42", "z42", "z42", "Z42", "z42", "Z42"),
|
||||
("A", "a", "A", "a", "a", "A", "a", "A"),
|
||||
("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_variant(original), original);
|
||||
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
||||
assert_eq!(UPPERCASE.apply_to_variant(original), upper);
|
||||
assert_eq!(PascalCase.apply_to_variant(original), original);
|
||||
assert_eq!(CamelCase.apply_to_variant(original), camel);
|
||||
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
||||
@@ -144,9 +152,10 @@ fn rename_variants() {
|
||||
|
||||
#[test]
|
||||
fn rename_fields() {
|
||||
for &(original, pascal, camel, screaming, kebab, screaming_kebab) in &[
|
||||
for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
|
||||
(
|
||||
"outcome",
|
||||
"OUTCOME",
|
||||
"Outcome",
|
||||
"outcome",
|
||||
"OUTCOME",
|
||||
@@ -155,16 +164,18 @@ fn rename_fields() {
|
||||
),
|
||||
(
|
||||
"very_tasty",
|
||||
"VERY_TASTY",
|
||||
"VeryTasty",
|
||||
"veryTasty",
|
||||
"VERY_TASTY",
|
||||
"very-tasty",
|
||||
"VERY-TASTY",
|
||||
),
|
||||
("a", "A", "a", "A", "a", "A"),
|
||||
("z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
||||
("a", "A", "A", "a", "A", "a", "A"),
|
||||
("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_field(original), original);
|
||||
assert_eq!(UPPERCASE.apply_to_field(original), upper);
|
||||
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
||||
assert_eq!(CamelCase.apply_to_field(original), camel);
|
||||
assert_eq!(SnakeCase.apply_to_field(original), original);
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ast::{Body, Container, Style};
|
||||
use attr::Identifier;
|
||||
use ast::{Data, Container, Style};
|
||||
use attr::{Identifier, EnumTag};
|
||||
use Ctxt;
|
||||
|
||||
/// Cross-cutting checks that require looking at more than a single attrs
|
||||
@@ -16,19 +16,21 @@ pub fn check(cx: &Ctxt, cont: &Container) {
|
||||
check_getter(cx, cont);
|
||||
check_identifier(cx, cont);
|
||||
check_variant_skip_attrs(cx, cont);
|
||||
check_internal_tag_field_name_conflict(cx, cont);
|
||||
check_adjacent_tag_conflict(cx, cont);
|
||||
}
|
||||
|
||||
/// Getters are only allowed inside structs (not enums) with the `remote`
|
||||
/// attribute.
|
||||
fn check_getter(cx: &Ctxt, cont: &Container) {
|
||||
match cont.body {
|
||||
Body::Enum(_) => {
|
||||
if cont.body.has_getter() {
|
||||
match cont.data {
|
||||
Data::Enum(_) => {
|
||||
if cont.data.has_getter() {
|
||||
cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
|
||||
}
|
||||
}
|
||||
Body::Struct(_, _) => {
|
||||
if cont.body.has_getter() && cont.attrs.remote().is_none() {
|
||||
Data::Struct(_, _) => {
|
||||
if cont.data.has_getter() && cont.attrs.remote().is_none() {
|
||||
cx.error(
|
||||
"#[serde(getter = \"...\")] can only be used in structs \
|
||||
that have #[serde(remote = \"...\")]",
|
||||
@@ -45,9 +47,9 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
|
||||
/// `field_identifier` all but possibly one variant must be unit variants. The
|
||||
/// last variant may be a newtype variant which is an implicit "other" case.
|
||||
fn check_identifier(cx: &Ctxt, cont: &Container) {
|
||||
let variants = match cont.body {
|
||||
Body::Enum(ref variants) => variants,
|
||||
Body::Struct(_, _) => {
|
||||
let variants = match cont.data {
|
||||
Data::Enum(ref variants) => variants,
|
||||
Data::Struct(_, _) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -102,9 +104,9 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
|
||||
/// Skip-(de)serializing attributes are not allowed on variants marked
|
||||
/// (de)serialize_with.
|
||||
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
||||
let variants = match cont.body {
|
||||
Body::Enum(ref variants) => variants,
|
||||
Body::Struct(_, _) => {
|
||||
let variants = match cont.data {
|
||||
Data::Enum(ref variants) => variants,
|
||||
Data::Struct(_, _) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -169,3 +171,67 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The tag of an internally-tagged struct variant must not be
|
||||
/// the same as either one of its fields, as this would result in
|
||||
/// duplicate keys in the serialized output and/or ambiguity in
|
||||
/// the to-be-deserialized input.
|
||||
fn check_internal_tag_field_name_conflict(
|
||||
cx: &Ctxt,
|
||||
cont: &Container,
|
||||
) {
|
||||
let variants = match cont.data {
|
||||
Data::Enum(ref variants) => variants,
|
||||
Data::Struct(_, _) => return,
|
||||
};
|
||||
|
||||
let tag = match *cont.attrs.tag() {
|
||||
EnumTag::Internal { ref tag } => tag.as_str(),
|
||||
EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
|
||||
};
|
||||
|
||||
let diagnose_conflict = || {
|
||||
let message = format!(
|
||||
"variant field name `{}` conflicts with internal tag",
|
||||
tag
|
||||
);
|
||||
cx.error(message);
|
||||
};
|
||||
|
||||
for variant in variants {
|
||||
match variant.style {
|
||||
Style::Struct => {
|
||||
for field in &variant.fields {
|
||||
let check_ser = !field.attrs.skip_serializing();
|
||||
let check_de = !field.attrs.skip_deserializing();
|
||||
let name = field.attrs.name();
|
||||
let ser_name = name.serialize_name();
|
||||
let de_name = name.deserialize_name();
|
||||
|
||||
if check_ser && ser_name == tag || check_de && de_name == tag {
|
||||
diagnose_conflict();
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
Style::Unit | Style::Newtype | Style::Tuple => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// In the case of adjacently-tagged enums, the type and the
|
||||
/// contents tag must differ, for the same reason.
|
||||
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
|
||||
let (type_tag, content_tag) = match *cont.attrs.tag() {
|
||||
EnumTag::Adjacent { ref tag, ref content } => (tag, content),
|
||||
EnumTag::Internal { .. } | EnumTag::External | EnumTag::None => return,
|
||||
};
|
||||
|
||||
if type_tag == content_tag {
|
||||
let message = format!(
|
||||
"enum tags `{}` for type and content conflict with each other",
|
||||
type_tag
|
||||
);
|
||||
cx.error(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,14 @@
|
||||
// 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.18.1")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.20.0")]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity, doc_markdown, match_same_arms,
|
||||
redundant_field_names))]
|
||||
|
||||
extern crate syn;
|
||||
#[macro_use]
|
||||
extern crate synom;
|
||||
extern crate syn;
|
||||
|
||||
extern crate proc_macro2;
|
||||
|
||||
pub mod ast;
|
||||
pub mod attr;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_test"
|
||||
version = "1.0.25" # remember to update html_root_url
|
||||
version = "1.0.30" # 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"
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
//! # use serde::ser::{Serialize, Serializer, SerializeMap};
|
||||
//! # use serde::de::{Deserialize, Deserializer, Visitor, MapAccess};
|
||||
//! #
|
||||
//! # // Dumb immitation of LinkedHashMap.
|
||||
//! # // Dumb imitation of LinkedHashMap.
|
||||
//! # #[derive(PartialEq, Debug)]
|
||||
//! # struct LinkedHashMap<K, V>(Vec<(K, V)>);
|
||||
//! #
|
||||
@@ -155,13 +155,14 @@
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.25")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.30")]
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||
// Whitelisted clippy lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
|
||||
// Whitelisted clippy_pedantic lints
|
||||
#![cfg_attr(feature = "cargo-clippy",
|
||||
allow(missing_docs_in_private_items, stutter, use_debug, use_self))]
|
||||
allow(empty_line_after_outer_attr, missing_docs_in_private_items,
|
||||
redundant_field_names, stutter, use_debug, use_self))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
@@ -9,6 +9,7 @@ unstable = ["serde/unstable", "compiletest_rs"]
|
||||
|
||||
[dev-dependencies]
|
||||
fnv = "1.0"
|
||||
proc-macro2 = "0.2"
|
||||
rustc-serialize = "0.3.16"
|
||||
serde = { path = "../serde", features = ["rc"] }
|
||||
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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
|
||||
#[serde(tag = "conflict", content = "conflict")]
|
||||
//~^^ HELP: enum tags `conflict` for type and content conflict with each other
|
||||
enum E {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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
|
||||
#[serde(tag = "conflict")]
|
||||
//~^^ HELP: variant field name `conflict` conflicts with internal tag
|
||||
enum E {
|
||||
A {
|
||||
#[serde(rename = "conflict")]
|
||||
x: (),
|
||||
},
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -6,6 +6,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(decimal_literal_representation))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#![deny(trivial_numeric_casts)]
|
||||
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ fn ip_addr_roundtrip() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn socked_addr_roundtrip() {
|
||||
fn socket_addr_roundtrip() {
|
||||
assert_tokens(
|
||||
&net::SocketAddr::from((*b"1234567890123456", 1234)).compact(),
|
||||
&seq![
|
||||
|
||||
Reference in New Issue
Block a user