From b9f5d226302fade1230bc9579d85a2c0617f1cdd Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 15 Mar 2015 15:31:31 -0700 Subject: [PATCH] Spring cleaning --- serde_macros/src/de.rs | 222 ++++++++++++++++++-------------------- serde_macros/src/field.rs | 25 ++++- 2 files changed, 126 insertions(+), 121 deletions(-) diff --git a/serde_macros/src/de.rs b/serde_macros/src/de.rs index 96bd1881..7ef23d29 100644 --- a/serde_macros/src/de.rs +++ b/serde_macros/src/de.rs @@ -1,7 +1,6 @@ use syntax::ast::{ Ident, MetaItem, - MetaItem_, Item, Expr, MutMutable, @@ -34,7 +33,7 @@ use syntax::ptr::P; use aster; -use field::struct_field_strs; +use field; pub fn expand_derive_deserialize( cx: &mut ExtCtxt, @@ -422,25 +421,12 @@ fn deserialize_struct_named_fields( ) -> P { let where_clause = &trait_generics.where_clause; - // Create the field names for the fields. - let field_names: Vec = (0 .. fields.len()) - .map(|i| builder.id(format!("__field{}", i))) - .collect(); - - let field_visitor = deserialize_field_visitor( + let (field_visitor, visit_map_expr) = deserialize_struct_visitor( cx, builder, - &field_names, struct_def, - ); - - let visit_map_expr = deserialize_map( - cx, - builder, struct_path, - &field_names, fields, - struct_def ); let struct_name = builder.expr().str(struct_ident); @@ -478,86 +464,6 @@ fn deserialize_struct_named_fields( }) } -fn deserialize_field_visitor( - cx: &ExtCtxt, - builder: &aster::AstBuilder, - field_names: &[ast::Ident], - struct_def: &StructDef, -) -> Vec> { - let field_enum = builder.item() - .attr().allow(&["non_camel_case_types"]) - .enum_("__Field") - .with_variants( - field_names.iter().map(|field| { - builder.variant(field).tuple().build() - }) - ) - .build(); - - // Get aliases - let aliases = struct_field_strs(cx, builder, struct_def); - - // Match arms to extract a field from a string - let field_arms: Vec = aliases.iter() - .zip(field_names.iter()) - .map(|(alias, field)| { - quote_arm!(cx, $alias => { Ok(__Field::$field) }) - }) - .collect(); - - vec![ - field_enum, - - quote_item!(cx, - impl ::serde::de::Deserialize for __Field { - #[inline] - fn deserialize(state: &mut S) -> Result<__Field, S::Error> - where S: ::serde::de::Deserializer, - { - struct __FieldVisitor; - - impl ::serde::de::Visitor for __FieldVisitor { - type Value = __Field; - - fn visit_str(&mut self, value: &str) -> Result<__Field, E> - where E: ::serde::de::Error, - { - match value { - $field_arms - _ => Err(::serde::de::Error::syntax_error()), - } - } - } - - state.visit(__FieldVisitor) - } - } - ).unwrap(), - ] -} - -fn default_value(field: &ast::StructField) -> bool { - field.node.attrs.iter() - .any(|sa| - if let MetaItem_::MetaList(ref n, ref vals) = sa.node.value.node { - if n == &"serde" { - vals.iter() - .map(|mi| - if let MetaItem_::MetaWord(ref n) = mi.node { - n == &"default" - } else { - false - }) - .any(|x| x) - } else { - false - } - } - else { - false - }) -} - fn deserialize_map( cx: &ExtCtxt, builder: &aster::AstBuilder, @@ -570,10 +476,10 @@ fn deserialize_map( let let_values: Vec> = field_names.iter() .zip(struct_def.fields.iter()) .map(|(field, sf)| { - if default_value(sf) { - quote_stmt!( - cx, - let mut $field = Some(::std::default::Default::default());) + if field::default_value(sf) { + quote_stmt!(cx, + let mut $field = Some(::std::default::Default::default()); + ) } else { quote_stmt!(cx, let mut $field = None;) } @@ -828,31 +734,17 @@ fn deserialize_enum_variant_map( ) -> P { let where_clause = &trait_generics.where_clause; - // Create the field names for the fields. - let field_names: Vec = (0 .. fields.len()) - .map(|i| builder.id(format!("__field{}", i))) - .collect(); + let struct_def = match variant.node.kind { + ast::VariantKind::StructVariantKind(ref struct_def) => struct_def, + _ => panic!("Mismatched enum types") + }; - let field_visitor = deserialize_field_visitor( - cx, - builder, - &field_names, - match variant.node.kind { - ast::VariantKind::StructVariantKind(ref sd) => &*sd, - _ => panic!("Mismatched enum types") - }, - ); - - let visit_map_expr = deserialize_map( + let (field_visitor, visit_map_expr) = deserialize_struct_visitor( cx, builder, + struct_def, variant_path, - &field_names, fields, - match variant.node.kind { - ast::VariantKind::StructVariantKind(ref sd) => &*sd, - _ => panic!("Mismatched enum types") - }, ); quote_expr!(cx, { @@ -875,3 +767,93 @@ fn deserialize_enum_variant_map( $state.visit_map($visitor_expr) }) } + +fn deserialize_field_visitor( + cx: &ExtCtxt, + builder: &aster::AstBuilder, + field_names: &[ast::Ident], + struct_def: &StructDef, +) -> Vec> { + let field_enum = builder.item() + .attr().allow(&["non_camel_case_types"]) + .enum_("__Field") + .with_variants( + field_names.iter().map(|field| { + builder.variant(field).tuple().build() + }) + ) + .build(); + + // Get aliases + let aliases = field::struct_field_strs(cx, builder, struct_def); + + // Match arms to extract a field from a string + let field_arms: Vec = aliases.iter() + .zip(field_names.iter()) + .map(|(alias, field)| { + quote_arm!(cx, $alias => { Ok(__Field::$field) }) + }) + .collect(); + + vec![ + field_enum, + + quote_item!(cx, + impl ::serde::de::Deserialize for __Field { + #[inline] + fn deserialize(state: &mut S) -> Result<__Field, S::Error> + where S: ::serde::de::Deserializer, + { + struct __FieldVisitor; + + impl ::serde::de::Visitor for __FieldVisitor { + type Value = __Field; + + fn visit_str(&mut self, value: &str) -> Result<__Field, E> + where E: ::serde::de::Error, + { + match value { + $field_arms + _ => Err(::serde::de::Error::syntax_error()), + } + } + } + + state.visit(__FieldVisitor) + } + } + ).unwrap(), + ] +} + +fn deserialize_struct_visitor( + cx: &ExtCtxt, + builder: &aster::AstBuilder, + struct_def: &ast::StructDef, + struct_path: ast::Path, + fields: &[Ident], +) -> (Vec>, P) { + + // Create the field names for the fields. + let field_names: Vec = (0 .. struct_def.fields.len()) + .map(|i| builder.id(format!("__field{}", i))) + .collect(); + + let field_visitor = deserialize_field_visitor( + cx, + builder, + &field_names, + struct_def, + ); + + let visit_map_expr = deserialize_map( + cx, + builder, + struct_path, + &field_names, + fields, + struct_def, + ); + + (field_visitor, visit_map_expr) +} diff --git a/serde_macros/src/field.rs b/serde_macros/src/field.rs index dc0aeaee..a4adc28b 100644 --- a/serde_macros/src/field.rs +++ b/serde_macros/src/field.rs @@ -4,7 +4,7 @@ use syntax::ptr::P; use aster; -pub fn field_alias(field: &ast::StructField) -> Option<&ast::Lit> { +fn field_alias(field: &ast::StructField) -> Option<&ast::Lit> { field.node.attrs.iter() .find(|sa| { if let ast::MetaList(ref n, _) = sa.node.value.node { @@ -55,3 +55,26 @@ pub fn struct_field_strs( }) .collect() } + +pub fn default_value(field: &ast::StructField) -> bool { + field.node.attrs.iter() + .any(|sa| { + if let ast::MetaItem_::MetaList(ref n, ref vals) = sa.node.value.node { + if n == &"serde" { + vals.iter() + .map(|mi| + if let ast::MetaItem_::MetaWord(ref n) = mi.node { + n == &"default" + } else { + false + }) + .any(|x| x) + } else { + false + } + } + else { + false + } + }) +}