ExprStruct --> Request

This commit is contained in:
Jimmy Cuadra 2018-05-04 17:30:20 -07:00
parent ba6eef9c76
commit a1929e38cf

View File

@ -1,23 +1,13 @@
use quote::{ToTokens, Tokens}; use quote::{ToTokens, Tokens};
use syn::synom::Synom; use syn::synom::Synom;
use syn::{Field, FieldsNamed, Meta, NestedMeta}; use syn::{ExprStruct, Field, FieldValue, FieldsNamed, Meta, NestedMeta};
use api::strip_serde_attrs; use api::strip_serde_attrs;
#[derive(Debug)]
pub struct Request { pub struct Request {
fields: Vec<RequestField>, fields: Vec<RequestField>,
} }
impl Synom for Request {
named!(parse -> Self, do_parse!(
fields: syn!(FieldsNamed) >>
(Request {
fields,
})
));
}
impl Request { impl Request {
pub fn has_body_fields(&self) -> bool { pub fn has_body_fields(&self) -> bool {
self.fields.iter().any(|field| field.is_body()) self.fields.iter().any(|field| field.is_body())
@ -35,7 +25,7 @@ impl Request {
self.fields.iter().filter(|field| field.is_path()).count() self.fields.iter().filter(|field| field.is_path()).count()
} }
pub fn newtype_body_field(&self) -> Option<&Field> { pub fn newtype_body_field(&self) -> Option<&FieldValue> {
for request_field in self.fields.iter() { for request_field in self.fields.iter() {
match *request_field { match *request_field {
RequestField::NewtypeBody(ref field) => { RequestField::NewtypeBody(ref field) => {
@ -75,41 +65,39 @@ impl Request {
} }
} }
impl From<Vec<Field>> for Request { impl From<ExprStruct> for Request {
fn from(fields: Vec<Field>) -> Self { fn from(expr: ExprStruct) -> Self {
let mut has_newtype_body = false; let mut has_newtype_body = false;
let request_fields = fields.into_iter().map(|mut field| { let fields = expr.fields.into_iter().map(|mut field_value| {
let mut request_field_kind = RequestFieldKind::Body; let mut field_kind = RequestFieldKind::Body;
field.attrs = field.attrs.into_iter().filter(|attr| { field_value.attrs = field_value.attrs.into_iter().filter(|attr| {
let (attr_ident, nested_meta_items) = match attr.value { let meta = attr.interpret_meta()
Meta::List(ref attr_ident, ref nested_meta_items) => (attr_ident, nested_meta_items), .expect("ruma_api! could not parse request field attributes");
_ => return true,
};
if attr_ident != "ruma_api" { let Meta::List(meta_list) = meta;
if meta_list.ident.as_ref() != "ruma_api" {
return true; return true;
} }
for nested_meta_item in nested_meta_items { for nested_meta_item in meta_list.nested {
match *nested_meta_item { match nested_meta_item {
NestedMeta::Meta(ref meta_item) => { NestedMeta::Meta(meta_item) => {
match *meta_item { match meta_item {
Meta::Word(ref ident) => { Meta::Word(ident) => {
if ident == "body" { match ident.as_ref() {
"body" => {
has_newtype_body = true; has_newtype_body = true;
request_field_kind = RequestFieldKind::NewtypeBody; field_kind = RequestFieldKind::NewtypeBody;
} else if ident == "header" { }
request_field_kind = RequestFieldKind::Header; "header" => field_kind = RequestFieldKind::Header,
} else if ident == "path" { "path" => field_kind = RequestFieldKind::Path,
request_field_kind = RequestFieldKind::Path; "query" => field_kind = RequestFieldKind::Query,
} else if ident == "query" { _ => panic!(
request_field_kind = RequestFieldKind::Query;
} else {
panic!(
"ruma_api! attribute meta item on requests must be: body, header, path, or query" "ruma_api! attribute meta item on requests must be: body, header, path, or query"
); ),
} }
} }
_ => panic!( _ => panic!(
@ -126,18 +114,18 @@ impl From<Vec<Field>> for Request {
false false
}).collect(); }).collect();
if request_field_kind == RequestFieldKind::Body { if field_kind == RequestFieldKind::Body {
assert!( assert!(
!has_newtype_body, !has_newtype_body,
"ruma_api! requests cannot have both normal body fields and a newtype body field" "ruma_api! requests cannot have both normal body fields and a newtype body field"
); );
} }
RequestField::new(request_field_kind, field) RequestField::new(field_kind, field_value)
}).collect(); }).collect();
Request { Request {
fields: request_fields, fields,
} }
} }
} }
@ -251,17 +239,16 @@ impl ToTokens for Request {
} }
} }
#[derive(Debug)]
pub enum RequestField { pub enum RequestField {
Body(Field), Body(FieldValue),
Header(Field), Header(FieldValue),
NewtypeBody(Field), NewtypeBody(FieldValue),
Path(Field), Path(FieldValue),
Query(Field), Query(FieldValue),
} }
impl RequestField { impl RequestField {
fn new(kind: RequestFieldKind, field: Field) -> RequestField { fn new(kind: RequestFieldKind, field: FieldValue) -> RequestField {
match kind { match kind {
RequestFieldKind::Body => RequestField::Body(field), RequestFieldKind::Body => RequestField::Body(field),
RequestFieldKind::Header => RequestField::Header(field), RequestFieldKind::Header => RequestField::Header(field),
@ -293,7 +280,7 @@ impl RequestField {
self.kind() == RequestFieldKind::Query self.kind() == RequestFieldKind::Query
} }
fn field(&self) -> &Field { fn field(&self) -> &FieldValue {
match *self { match *self {
RequestField::Body(ref field) => field, RequestField::Body(ref field) => field,
RequestField::Header(ref field) => field, RequestField::Header(ref field) => field,
@ -303,7 +290,7 @@ impl RequestField {
} }
} }
fn field_(&self, kind: RequestFieldKind) -> Option<&Field> { fn field_(&self, kind: RequestFieldKind) -> Option<&FieldValue> {
if self.kind() == kind { if self.kind() == kind {
Some(self.field()) Some(self.field())
} else { } else {