refactor(codegen): Add ContainerAttrs::from_items
This commit is contained in:
parent
0bd380ee23
commit
807224d231
@ -28,6 +28,35 @@ pub struct ContainerAttrs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ContainerAttrs {
|
impl ContainerAttrs {
|
||||||
|
/// Extract out the `#[serde(...)]` attributes from an item.
|
||||||
|
pub fn from_item(cx: &ExtCtxt, item: &ast::Item) -> Result<ContainerAttrs, Error> {
|
||||||
|
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 {
|
pub fn deny_unknown_fields(&self) -> bool {
|
||||||
self.deny_unknown_fields
|
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<Self, Error> {
|
|
||||||
for attr in attrs {
|
|
||||||
self = try!(self.attr(attr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn attr(mut self, attr: &ast::Attribute) -> Result<Self, Error> {
|
|
||||||
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<ast::MetaItem>) -> Result<Self, Error> {
|
|
||||||
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<ContainerAttrs, Error> {
|
|
||||||
let builder = ContainerAttrsBuilder::new(cx);
|
|
||||||
let builder = try!(builder.attrs(container.attrs()));
|
|
||||||
Ok(builder.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||||
pub fn get_struct_field_attrs(cx: &ExtCtxt,
|
pub fn get_struct_field_attrs(cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
@ -363,3 +319,13 @@ pub fn get_struct_field_attrs(cx: &ExtCtxt,
|
|||||||
|
|
||||||
Ok(attrs)
|
Ok(attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
|
||||||
|
match attr.node.value.node {
|
||||||
|
ast::MetaList(ref name, ref items) if name == &"serde" => {
|
||||||
|
attr::mark_used(&attr);
|
||||||
|
Some(items)
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,8 +14,7 @@ use syntax::ext::base::{Annotatable, ExtCtxt};
|
|||||||
use syntax::ext::build::AstBuilder;
|
use syntax::ext::build::AstBuilder;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
|
||||||
use attr::{self, ContainerAttrs};
|
use attr;
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
pub fn expand_derive_deserialize(
|
pub fn expand_derive_deserialize(
|
||||||
@ -88,7 +87,7 @@ fn deserialize_body(
|
|||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let container_attrs = try!(attr::get_container_attrs(cx, item));
|
let container_attrs = try!(attr::ContainerAttrs::from_item(cx, item));
|
||||||
|
|
||||||
match item.node {
|
match item.node {
|
||||||
ast::ItemStruct(ref variant_data, _) => {
|
ast::ItemStruct(ref variant_data, _) => {
|
||||||
@ -129,7 +128,7 @@ fn deserialize_item_struct(
|
|||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
span: Span,
|
span: Span,
|
||||||
variant_data: &ast::VariantData,
|
variant_data: &ast::VariantData,
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
match *variant_data {
|
match *variant_data {
|
||||||
ast::VariantData::Unit(_) => {
|
ast::VariantData::Unit(_) => {
|
||||||
@ -478,7 +477,7 @@ fn deserialize_struct(
|
|||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
@ -544,7 +543,7 @@ fn deserialize_item_enum(
|
|||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
enum_def: &EnumDef,
|
enum_def: &EnumDef,
|
||||||
container_attrs: &ContainerAttrs
|
container_attrs: &attr::ContainerAttrs
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
@ -642,7 +641,7 @@ fn deserialize_variant(
|
|||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
variant: &ast::Variant,
|
variant: &ast::Variant,
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let variant_ident = variant.node.name;
|
let variant_ident = variant.node.name;
|
||||||
|
|
||||||
@ -735,7 +734,7 @@ fn deserialize_struct_variant(
|
|||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let where_clause = &generics.where_clause;
|
let where_clause = &generics.where_clause;
|
||||||
|
|
||||||
@ -799,7 +798,7 @@ fn deserialize_field_visitor(
|
|||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
field_attrs: Vec<attr::FieldAttrs>,
|
field_attrs: Vec<attr::FieldAttrs>,
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Vec<P<ast::Item>> {
|
) -> Vec<P<ast::Item>> {
|
||||||
// Create the field names for the fields.
|
// Create the field names for the fields.
|
||||||
let field_idents: Vec<ast::Ident> = (0 .. field_attrs.len())
|
let field_idents: Vec<ast::Ident> = (0 .. field_attrs.len())
|
||||||
@ -963,7 +962,7 @@ fn deserialize_struct_visitor(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<(Vec<P<ast::Item>>, P<ast::Stmt>, P<ast::Expr>), Error> {
|
) -> Result<(Vec<P<ast::Item>>, P<ast::Stmt>, P<ast::Expr>), Error> {
|
||||||
let field_visitor = deserialize_field_visitor(
|
let field_visitor = deserialize_field_visitor(
|
||||||
cx,
|
cx,
|
||||||
@ -1006,7 +1005,7 @@ fn deserialize_map(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
// Create the field names for the fields.
|
// Create the field names for the fields.
|
||||||
let field_names: Vec<ast::Ident> = (0 .. fields.len())
|
let field_names: Vec<ast::Ident> = (0 .. fields.len())
|
||||||
|
@ -86,7 +86,7 @@ fn serialize_body(
|
|||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
// Note: While we don't have any container attributes, we still want to try to
|
// 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.
|
// 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 {
|
match item.node {
|
||||||
ast::ItemStruct(ref variant_data, _) => {
|
ast::ItemStruct(ref variant_data, _) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user