diff --git a/serde_codegen/src/attr.rs b/serde_codegen/src/attr.rs index a7d4af55..2c7b750a 100644 --- a/serde_codegen/src/attr.rs +++ b/serde_codegen/src/attr.rs @@ -28,6 +28,35 @@ pub struct ContainerAttrs { } impl ContainerAttrs { + /// Extract out the `#[serde(...)]` attributes from an item. + pub fn from_item(cx: &ExtCtxt, item: &ast::Item) -> Result { + let mut container_attrs = ContainerAttrs { + deny_unknown_fields: false, + }; + + for meta_items in item.attrs().iter().filter_map(get_serde_meta_items) { + for meta_item in meta_items { + match meta_item.node { + // Parse `#[serde(deny_unknown_fields)]` + ast::MetaWord(ref name) if name == &"deny_unknown_fields" => { + container_attrs.deny_unknown_fields = true; + } + + _ => { + cx.span_err( + meta_item.span, + &format!("unknown serde container attribute `{}`", + meta_item_to_string(meta_item))); + + return Err(Error); + } + } + } + } + + Ok(container_attrs) + } + pub fn deny_unknown_fields(&self) -> bool { self.deny_unknown_fields } @@ -275,79 +304,6 @@ impl<'a> FieldAttrsBuilder<'a> { } } -pub struct ContainerAttrsBuilder<'a> { - cx: &'a ExtCtxt<'a>, - deny_unknown_fields: bool, -} - -impl<'a> ContainerAttrsBuilder<'a> { - pub fn new(cx: &'a ExtCtxt) -> Self { - ContainerAttrsBuilder { - cx: cx, - deny_unknown_fields: false, - } - } - - pub fn attrs(mut self, attrs: &[ast::Attribute]) -> Result { - for attr in attrs { - self = try!(self.attr(attr)); - } - - Ok(self) - } - - pub fn attr(mut self, attr: &ast::Attribute) -> Result { - match attr.node.value.node { - ast::MetaList(ref name, ref items) if name == &"serde" => { - attr::mark_used(&attr); - for item in items { - self = try!(self.meta_item(item)); - } - - Ok(self) - } - _ => { - Ok(self) - } - } - } - - pub fn meta_item(self, meta_item: &P) -> Result { - match meta_item.node { - ast::MetaWord(ref name) if name == &"deny_unknown_fields" => { - Ok(self.deny_unknown_fields()) - } - _ => { - self.cx.span_err( - meta_item.span, - &format!("unknown serde container attribute `{}`", - meta_item_to_string(meta_item))); - Err(Error) - } - } - } - - pub fn deny_unknown_fields(mut self) -> Self { - self.deny_unknown_fields = true; - self - } - - pub fn build(self) -> ContainerAttrs { - ContainerAttrs { - deny_unknown_fields: self.deny_unknown_fields, - } - } -} - -/// Extract out the `#[serde(...)]` attributes from an item. -pub fn get_container_attrs(cx: &ExtCtxt, - container: &ast::Item, - ) -> Result { - let builder = ContainerAttrsBuilder::new(cx); - let builder = try!(builder.attrs(container.attrs())); - Ok(builder.build()) -} - /// Extract out the `#[serde(...)]` attributes from a struct field. pub fn get_struct_field_attrs(cx: &ExtCtxt, builder: &aster::AstBuilder, @@ -363,3 +319,13 @@ pub fn get_struct_field_attrs(cx: &ExtCtxt, Ok(attrs) } + +fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P]> { + match attr.node.value.node { + ast::MetaList(ref name, ref items) if name == &"serde" => { + attr::mark_used(&attr); + Some(items) + } + _ => None + } +} diff --git a/serde_codegen/src/de.rs b/serde_codegen/src/de.rs index 5a893e5f..f83892e6 100644 --- a/serde_codegen/src/de.rs +++ b/serde_codegen/src/de.rs @@ -14,8 +14,7 @@ use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::ptr::P; -use attr::{self, ContainerAttrs}; - +use attr; use error::Error; pub fn expand_derive_deserialize( @@ -88,7 +87,7 @@ fn deserialize_body( impl_generics: &ast::Generics, ty: P, ) -> Result, Error> { - let container_attrs = try!(attr::get_container_attrs(cx, item)); + let container_attrs = try!(attr::ContainerAttrs::from_item(cx, item)); match item.node { ast::ItemStruct(ref variant_data, _) => { @@ -129,7 +128,7 @@ fn deserialize_item_struct( ty: P, span: Span, variant_data: &ast::VariantData, - container_attrs: &ContainerAttrs, + container_attrs: &attr::ContainerAttrs, ) -> Result, Error> { match *variant_data { ast::VariantData::Unit(_) => { @@ -478,7 +477,7 @@ fn deserialize_struct( impl_generics: &ast::Generics, ty: P, fields: &[ast::StructField], - container_attrs: &ContainerAttrs, + container_attrs: &attr::ContainerAttrs, ) -> Result, Error> { let where_clause = &impl_generics.where_clause; @@ -544,7 +543,7 @@ fn deserialize_item_enum( impl_generics: &ast::Generics, ty: P, enum_def: &EnumDef, - container_attrs: &ContainerAttrs + container_attrs: &attr::ContainerAttrs ) -> Result, Error> { let where_clause = &impl_generics.where_clause; @@ -642,7 +641,7 @@ fn deserialize_variant( generics: &ast::Generics, ty: P, variant: &ast::Variant, - container_attrs: &ContainerAttrs, + container_attrs: &attr::ContainerAttrs, ) -> Result, Error> { let variant_ident = variant.node.name; @@ -735,7 +734,7 @@ fn deserialize_struct_variant( generics: &ast::Generics, ty: P, fields: &[ast::StructField], - container_attrs: &ContainerAttrs, + container_attrs: &attr::ContainerAttrs, ) -> Result, Error> { let where_clause = &generics.where_clause; @@ -799,7 +798,7 @@ fn deserialize_field_visitor( cx: &ExtCtxt, builder: &aster::AstBuilder, field_attrs: Vec, - container_attrs: &ContainerAttrs, + container_attrs: &attr::ContainerAttrs, ) -> Vec> { // Create the field names for the fields. let field_idents: Vec = (0 .. field_attrs.len()) @@ -963,7 +962,7 @@ fn deserialize_struct_visitor( builder: &aster::AstBuilder, struct_path: ast::Path, fields: &[ast::StructField], - container_attrs: &ContainerAttrs, + container_attrs: &attr::ContainerAttrs, ) -> Result<(Vec>, P, P), Error> { let field_visitor = deserialize_field_visitor( cx, @@ -1006,7 +1005,7 @@ fn deserialize_map( builder: &aster::AstBuilder, struct_path: ast::Path, fields: &[ast::StructField], - container_attrs: &ContainerAttrs, + container_attrs: &attr::ContainerAttrs, ) -> Result, Error> { // Create the field names for the fields. let field_names: Vec = (0 .. fields.len()) diff --git a/serde_codegen/src/ser.rs b/serde_codegen/src/ser.rs index 7a61c6a2..0c8ee210 100644 --- a/serde_codegen/src/ser.rs +++ b/serde_codegen/src/ser.rs @@ -86,7 +86,7 @@ fn serialize_body( ) -> Result, Error> { // Note: While we don't have any container attributes, we still want to try to // parse them so we can report a proper error if we get passed an unknown attribute. - let _ = try!(attr::get_container_attrs(cx, item)); + let _container_attrs = try!(attr::ContainerAttrs::from_item(cx, item)); match item.node { ast::ItemStruct(ref variant_data, _) => {