From 7ada27014dd2a79b03a92244889208a8bf1d89fe Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 19 May 2018 20:47:40 -0700 Subject: [PATCH] Track field index in internal AST --- serde_derive/src/de.rs | 56 ++++++++++------------------ serde_derive/src/internals/ast.rs | 7 +++- serde_derive/src/internals/check.rs | 28 +++++++------- serde_derive/src/pretend.rs | 8 ++-- serde_derive/src/ser.rs | 57 +++++++++++------------------ 5 files changed, 66 insertions(+), 90 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index fd2328fb..1498e4a7 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -275,15 +275,9 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { 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) } 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) } Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), @@ -637,7 +631,7 @@ fn deserialize_seq( }); let mut result = if is_struct { - let names = fields.iter().map(|f| &f.ident); + let names = fields.iter().map(|f| &f.member); quote! { #type_path { #( #names: #vars ),* } } @@ -700,20 +694,13 @@ fn deserialize_seq_in_place( let write_values = vars .clone() .zip(fields) - .enumerate() - .map(|(field_index, (_, field))| { - // 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(), - }) - }); + .map(|(_, field)| { + let member = &field.member; if field.attrs.skip_deserializing() { let default = Expr(expr_is_missing(field, cattrs)); quote! { - self.place.#field_name = #default; + self.place.#member = #default; } } else { let return_invalid_length = quote! { @@ -723,7 +710,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.#member))) { #return_invalid_length } @@ -736,7 +723,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.#member = __wrap.value; } _serde::export::None => { #return_invalid_length @@ -2425,12 +2412,12 @@ fn deserialize_map( }; 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() { let value = Expr(expr_is_missing(field, cattrs)); - quote!(#ident: #value) + quote!(#member: #value) } else { - quote!(#ident: #name) + quote!(#member: #name) } }); @@ -2535,19 +2522,19 @@ fn deserialize_map_in_place( .filter(|&&(field, _)| !field.attrs.skip_deserializing()) .map(|&(field, ref 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() { None => { 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) => { let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); quote!({ #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 { - let field_name = field.ident; + let member = &field.member; let missing_expr = Expr(missing_expr); quote! { 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 { Style::Struct if variant.fields.len() == 1 => { - let field_ident = variant.fields[0].ident.unwrap(); + let member = &variant.fields[0].member; quote! { - |__wrap| #this::#variant_ident { #field_ident: __wrap.value } + |__wrap| #this::#variant_ident { #member: __wrap.value } } } Style::Struct => { - let field_idents = variant - .fields - .iter() - .map(|field| field.ident.as_ref().unwrap()); + let members = variant.fields.iter().map(|field| &field.member); quote! { - |__wrap| #this::#variant_ident { #(#field_idents: __wrap.value.#field_access),* } + |__wrap| #this::#variant_ident { #(#members: __wrap.value.#field_access),* } } } Style::Tuple => quote! { @@ -2761,8 +2745,8 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment { match *cattrs.default() { attr::Default::Default | attr::Default::Path(_) => { - let ident = field.ident; - return quote_expr!(__default.#ident); + let member = &field.member; + return quote_expr!(__default.#member); } attr::Default::None => { /* below */ } } diff --git a/serde_derive/src/internals/ast.rs b/serde_derive/src/internals/ast.rs index 9ccb62f5..1013be2c 100644 --- a/serde_derive/src/internals/ast.rs +++ b/serde_derive/src/internals/ast.rs @@ -32,7 +32,7 @@ pub struct Variant<'a> { } pub struct Field<'a> { - pub ident: Option, + pub member: syn::Member, pub attrs: attr::Field, pub ty: &'a syn::Type, pub original: &'a syn::Field, @@ -166,7 +166,10 @@ fn fields_from_ast<'a>( .iter() .enumerate() .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), ty: &field.ty, original: field, diff --git a/serde_derive/src/internals/check.rs b/serde_derive/src/internals/check.rs index 00188ac6..eac1c229 100644 --- a/serde_derive/src/internals/check.rs +++ b/serde_derive/src/internals/check.rs @@ -9,6 +9,7 @@ use internals::ast::{Container, Data, Field, Style}; use internals::attr::{EnumTag, Identifier}; use internals::Ctxt; +use syn::Member; /// Cross-cutting checks that require looking at more than a single 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() { - let ident = field - .ident - .as_ref() - .map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident)); + for field in &variant.fields { + let member = member_message(&field.member); if field.attrs.skip_serializing() { cx.error(format!( "variant `{}` cannot have both #[serde(serialize_with)] and \ 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!( "variant `{}` cannot have both #[serde(serialize_with)] and \ 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() { - let ident = field - .ident - .as_ref() - .map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident)); + let member = member_message(&field.member); cx.error(format!( "variant `{}` cannot have both #[serde(deserialize_with)] \ 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); } } + +fn member_message(member: &Member) -> String { + match *member { + Member::Named(ref ident) => format!("`{}`", ident), + Member::Unnamed(ref i) => i.index.to_string(), + } +} diff --git a/serde_derive/src/pretend.rs b/serde_derive/src/pretend.rs index ac2878f1..cd51b4dd 100644 --- a/serde_derive/src/pretend.rs +++ b/serde_derive/src/pretend.rs @@ -113,8 +113,8 @@ fn pretend_variants_used(cont: &Container) -> Tokens { let pat = match variant.style { Style::Struct => { - let names = variant.fields.iter().map(|field| field.ident); - quote!({ #(#names: #placeholders),* }) + let members = variant.fields.iter().map(|field| &field.member); + quote!({ #(#members: #placeholders),* }) } Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )), Style::Unit => quote!(), @@ -134,8 +134,8 @@ fn pretend_variants_used(cont: &Container) -> 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 = (0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site())); - quote!({ #(#names: ref #placeholders),* }) + quote!({ #(#members: ref #placeholders),* }) } diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 71d247c0..710cc69e 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -173,15 +173,9 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment { 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) } 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) } Data::Struct(Style::Newtype, ref fields) => { @@ -305,8 +299,7 @@ fn serialize_struct_as_struct( .map(|field| match field.attrs.skip_serializing_if() { None => quote!(1), Some(path) => { - let ident = field.ident.expect("struct has unnamed fields"); - let field_expr = get_member(params, field, &Member::Named(ident)); + let field_expr = get_member(params, field, &field.member); 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() { None => quote!(1), Some(path) => { - let ident = field.ident.expect("struct has unnamed fields"); - let field_expr = get_member(params, field, &Member::Named(ident)); + let field_expr = get_member(params, field, &field.member); quote!(if #path(#field_expr) { 0 } else { 1 }) } }) @@ -424,12 +416,9 @@ fn serialize_variant( } } Style::Struct => { - let fields = variant - .fields - .iter() - .map(|f| f.ident.expect("struct variant has unnamed fields")); + let members = variant.fields.iter().map(|f| &f.member); quote! { - #this::#variant_ident { #(ref #fields),* } + #this::#variant_ident { #(ref #members),* } } } }; @@ -657,15 +646,11 @@ fn serialize_adjacently_tagged_variant( 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()) - .map(|i| Ident::new(&format!("__field{}", i), Span::call_site())) - .collect(), - Style::Struct => variant - .fields - .iter() - .map(|f| f.ident.expect("struct variant has unnamed fields")) + .map(|i| Member::Named(Ident::new(&format!("__field{}", i), Span::call_site()))) .collect(), + Style::Struct => variant.fields.iter().map(|f| f.member.clone()).collect(), }; let (_, ty_generics, where_clause) = params.generics.split_for_impl(); @@ -851,10 +836,10 @@ fn serialize_struct_variant<'a>( let len = serialized_fields .map(|field| { - let ident = field.ident.expect("struct has unnamed fields"); + let member = &field.member; 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), } }) @@ -930,7 +915,7 @@ fn serialize_struct_variant_with_flatten<'a>( } => { let this = ¶ms.this; let fields_ty = fields.iter().map(|f| &f.ty); - let fields_ident = &fields.iter().map(|f| f.ident).collect::>(); + let members = &fields.iter().map(|f| &f.member).collect::>(); let (_, ty_generics, where_clause) = params.generics.split_for_impl(); let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a"); @@ -947,7 +932,7 @@ fn serialize_struct_variant_with_flatten<'a>( where __S: _serde::Serializer, { - let (#(#fields_ident,)*) = self.data; + let (#(#members,)*) = self.data; let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( __serializer, _serde::export::None)); @@ -962,7 +947,7 @@ fn serialize_struct_variant_with_flatten<'a>( #variant_index, #variant_name, &__EnumFlatten { - data: (#(#fields_ident,)*), + data: (#(#members,)*), phantom: _serde::export::PhantomData::<#this #ty_generics>, }) } @@ -1051,12 +1036,12 @@ fn serialize_struct_visitor( .iter() .filter(|&field| !field.attrs.skip_serializing()) .map(|field| { - let field_ident = field.ident.expect("struct has unnamed field"); + let member = &field.member; let mut field_expr = if is_enum { - quote!(#field_ident) + quote!(#member) } else { - get_member(params, field, &Member::Named(field_ident)) + get_member(params, field, &member) }; let key_expr = field.attrs.name().serialize_name(); @@ -1124,11 +1109,13 @@ fn wrap_serialize_variant_with( let field_exprs: Vec<_> = variant .fields .iter() - .enumerate() - .map(|(i, field)| { - let id = field - .ident - .unwrap_or_else(|| Ident::new(&format!("__field{}", i), Span::call_site())); + .map(|field| { + let id = match field.member { + Member::Named(ident) => ident, + Member::Unnamed(ref member) => { + Ident::new(&format!("__field{}", member.index), Span::call_site()) + } + }; quote!(#id) }) .collect();