Track field index in internal AST

This commit is contained in:
David Tolnay
2018-05-19 20:47:40 -07:00
parent 4fa2a50f62
commit 7ada27014d
5 changed files with 66 additions and 90 deletions
+20 -36
View File
@@ -275,15 +275,9 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
match cont.data { match cont.data {
Data::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs), Data::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, ref fields) => { 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)
} }
Data::Struct(Style::Tuple, ref fields) | Data::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) deserialize_tuple(None, params, fields, &cont.attrs, None)
} }
Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs),
@@ -637,7 +631,7 @@ fn deserialize_seq(
}); });
let mut result = if is_struct { let mut result = if is_struct {
let names = fields.iter().map(|f| &f.ident); let names = fields.iter().map(|f| &f.member);
quote! { quote! {
#type_path { #( #names: #vars ),* } #type_path { #( #names: #vars ),* }
} }
@@ -700,20 +694,13 @@ fn deserialize_seq_in_place(
let write_values = vars let write_values = vars
.clone() .clone()
.zip(fields) .zip(fields)
.enumerate() .map(|(_, field)| {
.map(|(field_index, (_, field))| { let member = &field.member;
// If there's no field name, assume we're a tuple-struct and use a numeric index
let field_name = field.ident.map(Member::Named).unwrap_or_else(|| {
Member::Unnamed(Index {
index: field_index as u32,
span: Span::call_site(),
})
});
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let default = Expr(expr_is_missing(field, cattrs)); let default = Expr(expr_is_missing(field, cattrs));
quote! { quote! {
self.place.#field_name = #default; self.place.#member = #default;
} }
} else { } else {
let return_invalid_length = quote! { let return_invalid_length = quote! {
@@ -723,7 +710,7 @@ fn deserialize_seq_in_place(
None => { None => {
quote! { quote! {
if let _serde::export::None = try!(_serde::de::SeqAccess::next_element_seed(&mut __seq, 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.#member)))
{ {
#return_invalid_length #return_invalid_length
} }
@@ -736,7 +723,7 @@ fn deserialize_seq_in_place(
#wrapper #wrapper
match try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)) { match try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)) {
_serde::export::Some(__wrap) => { _serde::export::Some(__wrap) => {
self.place.#field_name = __wrap.value; self.place.#member = __wrap.value;
} }
_serde::export::None => { _serde::export::None => {
#return_invalid_length #return_invalid_length
@@ -2425,12 +2412,12 @@ fn deserialize_map(
}; };
let result = fields_names.iter().map(|&(field, ref name)| { let result = fields_names.iter().map(|&(field, ref name)| {
let ident = field.ident.expect("struct contains unnamed fields"); let member = &field.member;
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let value = Expr(expr_is_missing(field, cattrs)); let value = Expr(expr_is_missing(field, cattrs));
quote!(#ident: #value) quote!(#member: #value)
} else { } else {
quote!(#ident: #name) quote!(#member: #name)
} }
}); });
@@ -2535,19 +2522,19 @@ fn deserialize_map_in_place(
.filter(|&&(field, _)| !field.attrs.skip_deserializing()) .filter(|&&(field, _)| !field.attrs.skip_deserializing())
.map(|&(field, ref name)| { .map(|&(field, ref name)| {
let deser_name = field.attrs.name().deserialize_name(); let deser_name = field.attrs.name().deserialize_name();
let field_name = field.ident; let member = &field.member;
let visit = match field.attrs.deserialize_with() { let visit = match field.attrs.deserialize_with() {
None => { None => {
quote! { quote! {
try!(_serde::de::MapAccess::next_value_seed(&mut __map, _serde::private::de::InPlaceSeed(&mut self.place.#field_name))) try!(_serde::de::MapAccess::next_value_seed(&mut __map, _serde::private::de::InPlaceSeed(&mut self.place.#member)))
} }
} }
Some(path) => { Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote!({ quote!({
#wrapper #wrapper
self.place.#field_name = try!(_serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map)).value self.place.#member = try!(_serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map)).value
}) })
} }
}; };
@@ -2610,11 +2597,11 @@ fn deserialize_map_in_place(
} }
} }
} else { } else {
let field_name = field.ident; let member = &field.member;
let missing_expr = Expr(missing_expr); let missing_expr = Expr(missing_expr);
quote! { quote! {
if !#name { if !#name {
self.place.#field_name = #missing_expr; self.place.#member = #missing_expr;
}; };
} }
} }
@@ -2720,18 +2707,15 @@ fn wrap_deserialize_variant_with(
}); });
let unwrap_fn = match variant.style { let unwrap_fn = match variant.style {
Style::Struct if variant.fields.len() == 1 => { Style::Struct if variant.fields.len() == 1 => {
let field_ident = variant.fields[0].ident.unwrap(); let member = &variant.fields[0].member;
quote! { quote! {
|__wrap| #this::#variant_ident { #field_ident: __wrap.value } |__wrap| #this::#variant_ident { #member: __wrap.value }
} }
} }
Style::Struct => { Style::Struct => {
let field_idents = variant let members = variant.fields.iter().map(|field| &field.member);
.fields
.iter()
.map(|field| field.ident.as_ref().unwrap());
quote! { quote! {
|__wrap| #this::#variant_ident { #(#field_idents: __wrap.value.#field_access),* } |__wrap| #this::#variant_ident { #(#members: __wrap.value.#field_access),* }
} }
} }
Style::Tuple => quote! { Style::Tuple => quote! {
@@ -2761,8 +2745,8 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
match *cattrs.default() { match *cattrs.default() {
attr::Default::Default | attr::Default::Path(_) => { attr::Default::Default | attr::Default::Path(_) => {
let ident = field.ident; let member = &field.member;
return quote_expr!(__default.#ident); return quote_expr!(__default.#member);
} }
attr::Default::None => { /* below */ } attr::Default::None => { /* below */ }
} }
+5 -2
View File
@@ -32,7 +32,7 @@ pub struct Variant<'a> {
} }
pub struct Field<'a> { pub struct Field<'a> {
pub ident: Option<syn::Ident>, pub member: syn::Member,
pub attrs: attr::Field, pub attrs: attr::Field,
pub ty: &'a syn::Type, pub ty: &'a syn::Type,
pub original: &'a syn::Field, pub original: &'a syn::Field,
@@ -166,7 +166,10 @@ fn fields_from_ast<'a>(
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, field)| Field { .map(|(i, field)| Field {
ident: field.ident, member: match field.ident {
Some(ident) => syn::Member::Named(ident),
None => syn::Member::Unnamed(i.into()),
},
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default), attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
ty: &field.ty, ty: &field.ty,
original: field, original: field,
+15 -13
View File
@@ -9,6 +9,7 @@
use internals::ast::{Container, Data, Field, Style}; use internals::ast::{Container, Data, Field, Style};
use internals::attr::{EnumTag, Identifier}; use internals::attr::{EnumTag, Identifier};
use internals::Ctxt; use internals::Ctxt;
use syn::Member;
/// Cross-cutting checks that require looking at more than a single attrs /// Cross-cutting checks that require looking at more than a single attrs
/// object. Simpler checks should happen when parsing and building the attrs. /// object. Simpler checks should happen when parsing and building the attrs.
@@ -171,17 +172,14 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
)); ));
} }
for (i, field) in variant.fields.iter().enumerate() { for field in &variant.fields {
let ident = field let member = member_message(&field.member);
.ident
.as_ref()
.map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));
if field.attrs.skip_serializing() { if field.attrs.skip_serializing() {
cx.error(format!( cx.error(format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \ "variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing)]", a field {} marked with #[serde(skip_serializing)]",
variant.ident, ident variant.ident, member
)); ));
} }
@@ -189,7 +187,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
cx.error(format!( cx.error(format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \ "variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing_if)]", a field {} marked with #[serde(skip_serializing_if)]",
variant.ident, ident variant.ident, member
)); ));
} }
} }
@@ -204,17 +202,14 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
)); ));
} }
for (i, field) in variant.fields.iter().enumerate() { for field in &variant.fields {
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let ident = field let member = member_message(&field.member);
.ident
.as_ref()
.map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));
cx.error(format!( cx.error(format!(
"variant `{}` cannot have both #[serde(deserialize_with)] \ "variant `{}` cannot have both #[serde(deserialize_with)] \
and a field {} marked with #[serde(skip_deserializing)]", and a field {} marked with #[serde(skip_deserializing)]",
variant.ident, ident variant.ident, member
)); ));
} }
} }
@@ -282,3 +277,10 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
cx.error(message); cx.error(message);
} }
} }
fn member_message(member: &Member) -> String {
match *member {
Member::Named(ref ident) => format!("`{}`", ident),
Member::Unnamed(ref i) => i.index.to_string(),
}
}
+4 -4
View File
@@ -113,8 +113,8 @@ fn pretend_variants_used(cont: &Container) -> Tokens {
let pat = match variant.style { let pat = match variant.style {
Style::Struct => { Style::Struct => {
let names = variant.fields.iter().map(|field| field.ident); let members = variant.fields.iter().map(|field| &field.member);
quote!({ #(#names: #placeholders),* }) quote!({ #(#members: #placeholders),* })
} }
Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )), Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )),
Style::Unit => quote!(), Style::Unit => quote!(),
@@ -134,8 +134,8 @@ fn pretend_variants_used(cont: &Container) -> Tokens {
} }
fn struct_pattern(fields: &[Field]) -> Tokens { fn struct_pattern(fields: &[Field]) -> Tokens {
let names = fields.iter().map(|field| field.ident); let members = fields.iter().map(|field| &field.member);
let placeholders = let placeholders =
(0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site())); (0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
quote!({ #(#names: ref #placeholders),* }) quote!({ #(#members: ref #placeholders),* })
} }
+22 -35
View File
@@ -173,15 +173,9 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
match cont.data { match cont.data {
Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs), Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, ref fields) => { 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) serialize_struct(params, fields, &cont.attrs)
} }
Data::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) serialize_tuple_struct(params, fields, &cont.attrs)
} }
Data::Struct(Style::Newtype, ref fields) => { Data::Struct(Style::Newtype, ref fields) => {
@@ -305,8 +299,7 @@ fn serialize_struct_as_struct(
.map(|field| match field.attrs.skip_serializing_if() { .map(|field| match field.attrs.skip_serializing_if() {
None => quote!(1), None => quote!(1),
Some(path) => { Some(path) => {
let ident = field.ident.expect("struct has unnamed fields"); let field_expr = get_member(params, field, &field.member);
let field_expr = get_member(params, field, &Member::Named(ident));
quote!(if #path(#field_expr) { 0 } else { 1 }) quote!(if #path(#field_expr) { 0 } else { 1 })
} }
}) })
@@ -341,8 +334,7 @@ fn serialize_struct_as_map(
.map(|field| match field.attrs.skip_serializing_if() { .map(|field| match field.attrs.skip_serializing_if() {
None => quote!(1), None => quote!(1),
Some(path) => { Some(path) => {
let ident = field.ident.expect("struct has unnamed fields"); let field_expr = get_member(params, field, &field.member);
let field_expr = get_member(params, field, &Member::Named(ident));
quote!(if #path(#field_expr) { 0 } else { 1 }) quote!(if #path(#field_expr) { 0 } else { 1 })
} }
}) })
@@ -424,12 +416,9 @@ fn serialize_variant(
} }
} }
Style::Struct => { Style::Struct => {
let fields = variant let members = variant.fields.iter().map(|f| &f.member);
.fields
.iter()
.map(|f| f.ident.expect("struct variant has unnamed fields"));
quote! { quote! {
#this::#variant_ident { #(ref #fields),* } #this::#variant_ident { #(ref #members),* }
} }
} }
}; };
@@ -657,15 +646,11 @@ fn serialize_adjacently_tagged_variant(
unreachable!() unreachable!()
} }
} }
Style::Newtype => vec![Ident::new("__field0", Span::call_site())], Style::Newtype => vec![Member::Named(Ident::new("__field0", Span::call_site()))],
Style::Tuple => (0..variant.fields.len()) Style::Tuple => (0..variant.fields.len())
.map(|i| Ident::new(&format!("__field{}", i), Span::call_site())) .map(|i| Member::Named(Ident::new(&format!("__field{}", i), Span::call_site())))
.collect(),
Style::Struct => variant
.fields
.iter()
.map(|f| f.ident.expect("struct variant has unnamed fields"))
.collect(), .collect(),
Style::Struct => variant.fields.iter().map(|f| f.member.clone()).collect(),
}; };
let (_, ty_generics, where_clause) = params.generics.split_for_impl(); let (_, ty_generics, where_clause) = params.generics.split_for_impl();
@@ -851,10 +836,10 @@ fn serialize_struct_variant<'a>(
let len = serialized_fields let len = serialized_fields
.map(|field| { .map(|field| {
let ident = field.ident.expect("struct has unnamed fields"); let member = &field.member;
match field.attrs.skip_serializing_if() { match field.attrs.skip_serializing_if() {
Some(path) => quote!(if #path(#ident) { 0 } else { 1 }), Some(path) => quote!(if #path(#member) { 0 } else { 1 }),
None => quote!(1), None => quote!(1),
} }
}) })
@@ -930,7 +915,7 @@ fn serialize_struct_variant_with_flatten<'a>(
} => { } => {
let this = &params.this; let this = &params.this;
let fields_ty = fields.iter().map(|f| &f.ty); let fields_ty = fields.iter().map(|f| &f.ty);
let fields_ident = &fields.iter().map(|f| f.ident).collect::<Vec<_>>(); let members = &fields.iter().map(|f| &f.member).collect::<Vec<_>>();
let (_, ty_generics, where_clause) = params.generics.split_for_impl(); let (_, ty_generics, where_clause) = params.generics.split_for_impl();
let wrapper_generics = bound::with_lifetime_bound(&params.generics, "'__a"); let wrapper_generics = bound::with_lifetime_bound(&params.generics, "'__a");
@@ -947,7 +932,7 @@ fn serialize_struct_variant_with_flatten<'a>(
where where
__S: _serde::Serializer, __S: _serde::Serializer,
{ {
let (#(#fields_ident,)*) = self.data; let (#(#members,)*) = self.data;
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
__serializer, __serializer,
_serde::export::None)); _serde::export::None));
@@ -962,7 +947,7 @@ fn serialize_struct_variant_with_flatten<'a>(
#variant_index, #variant_index,
#variant_name, #variant_name,
&__EnumFlatten { &__EnumFlatten {
data: (#(#fields_ident,)*), data: (#(#members,)*),
phantom: _serde::export::PhantomData::<#this #ty_generics>, phantom: _serde::export::PhantomData::<#this #ty_generics>,
}) })
} }
@@ -1051,12 +1036,12 @@ fn serialize_struct_visitor(
.iter() .iter()
.filter(|&field| !field.attrs.skip_serializing()) .filter(|&field| !field.attrs.skip_serializing())
.map(|field| { .map(|field| {
let field_ident = field.ident.expect("struct has unnamed field"); let member = &field.member;
let mut field_expr = if is_enum { let mut field_expr = if is_enum {
quote!(#field_ident) quote!(#member)
} else { } else {
get_member(params, field, &Member::Named(field_ident)) get_member(params, field, &member)
}; };
let key_expr = field.attrs.name().serialize_name(); let key_expr = field.attrs.name().serialize_name();
@@ -1124,11 +1109,13 @@ fn wrap_serialize_variant_with(
let field_exprs: Vec<_> = variant let field_exprs: Vec<_> = variant
.fields .fields
.iter() .iter()
.enumerate() .map(|field| {
.map(|(i, field)| { let id = match field.member {
let id = field Member::Named(ident) => ident,
.ident Member::Unnamed(ref member) => {
.unwrap_or_else(|| Ident::new(&format!("__field{}", i), Span::call_site())); Ident::new(&format!("__field{}", member.index), Span::call_site())
}
};
quote!(#id) quote!(#id)
}) })
.collect(); .collect();