From 24370f3d4c03d3b5d0209a074cd8e48e2b89d340 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 14 May 2017 17:34:21 -0700 Subject: [PATCH] Change syntax for meta items and remove them after use. --- src/request.rs | 85 +++++++++++++++++++++++++++++++++---------------- src/response.rs | 70 +++++++++++++++++++++++++++++----------- 2 files changed, 109 insertions(+), 46 deletions(-) diff --git a/src/request.rs b/src/request.rs index 0e4d4992..90dba2fc 100644 --- a/src/request.rs +++ b/src/request.rs @@ -1,5 +1,5 @@ use quote::{ToTokens, Tokens}; -use syn::{Field, Lit, MetaItem}; +use syn::{Field, MetaItem, NestedMetaItem}; #[derive(Debug)] pub struct Request { @@ -37,34 +37,56 @@ impl Request { impl From> for Request { fn from(fields: Vec) -> Self { - let request_fields = fields.into_iter().map(|field| { - for attr in field.attrs.clone().iter() { - match attr.value { - MetaItem::Word(ref ident) => { - if ident == "query" { - return RequestField::Query(field); - } - } - MetaItem::List(_, _) => {} - MetaItem::NameValue(ref ident, ref lit) => { - if ident == "header" { - if let Lit::Str(ref name, _) = *lit { - return RequestField::Header(name.clone(), field); - } else { - panic!("ruma_api! header attribute expects a string value"); - } - } else if ident == "path" { - if let Lit::Str(ref name, _) = *lit { - return RequestField::Path(name.clone(), field); - } else { - panic!("ruma_api! path attribute expects a string value"); + let request_fields = fields.into_iter().map(|mut field| { + let mut request_field_kind = RequestFieldKind::Body; + + field.attrs = field.attrs.into_iter().filter(|attr| { + let (attr_ident, nested_meta_items) = match attr.value { + MetaItem::List(ref attr_ident, ref nested_meta_items) => (attr_ident, nested_meta_items), + _ => return true, + }; + + if attr_ident != "ruma_api" { + return true; + } + + for nested_meta_item in nested_meta_items { + match *nested_meta_item { + NestedMetaItem::MetaItem(ref meta_item) => { + match *meta_item { + MetaItem::Word(ref ident) => { + if ident == "header" { + request_field_kind = RequestFieldKind::Header; + } else if ident == "path" { + request_field_kind = RequestFieldKind::Path; + } else if ident == "query" { + request_field_kind = RequestFieldKind::Query; + } else { + panic!( + "ruma_api! attribute meta item on requests must be: header, path, or query" + ); + } + } + _ => panic!( + "ruma_api! attribute meta item on requests cannot be a list or name/value pair" + ), } } + NestedMetaItem::Literal(_) => panic!( + "ruma_api! attribute meta item on requests must be: header, path, or query" + ), } } - } - return RequestField::Body(field); + false + }).collect(); + + match request_field_kind { + RequestFieldKind::Body => RequestField::Body(field), + RequestFieldKind::Header => RequestField::Header(field), + RequestFieldKind::Path => RequestField::Path(field), + RequestFieldKind::Query => RequestField::Query(field), + } }).collect(); Request { @@ -89,8 +111,8 @@ impl ToTokens for Request { for request_field in self.fields.iter() { match *request_field { RequestField::Body(ref field) => field.to_tokens(&mut tokens), - RequestField::Header(_, ref field) => field.to_tokens(&mut tokens), - RequestField::Path(_, ref field) => field.to_tokens(&mut tokens), + RequestField::Header(ref field) => field.to_tokens(&mut tokens), + RequestField::Path(ref field) => field.to_tokens(&mut tokens), RequestField::Query(ref field) => field.to_tokens(&mut tokens), } @@ -128,8 +150,8 @@ impl ToTokens for Request { #[derive(Debug)] pub enum RequestField { Body(Field), - Header(String, Field), - Path(String, Field), + Header(Field), + Path(Field), Query(Field), } @@ -142,6 +164,13 @@ impl RequestField { } } +enum RequestFieldKind { + Body, + Header, + Path, + Query, +} + #[derive(Debug)] pub struct RequestBodyFields<'a> { fields: &'a [RequestField], diff --git a/src/response.rs b/src/response.rs index beb83428..e2068e26 100644 --- a/src/response.rs +++ b/src/response.rs @@ -1,5 +1,5 @@ use quote::{ToTokens, Tokens}; -use syn::{Field, Lit, MetaItem}; +use syn::{Field, MetaItem, NestedMetaItem}; #[derive(Debug)] pub struct Response { @@ -28,14 +28,14 @@ impl Response { #field_name: response_body.#field_name, }); } - ResponseField::Header(ref name, ref field) => { + ResponseField::Header(ref field) => { let field_name = field.ident.as_ref() .expect("expected body field to have a name"); tokens.append(quote! { #field_name: hyper_response.headers() - .get_raw(#name) - .expect("missing expected request header: {}", #name), + .get_raw(#field_name) + .expect("missing expected request header: {}", #field_name), }); } } @@ -47,23 +47,52 @@ impl Response { impl From> for Response { fn from(fields: Vec) -> Self { - let response_fields = fields.into_iter().map(|field| { - for attr in field.attrs.clone().iter() { - match attr.value { - MetaItem::Word(_) | MetaItem::List(_, _) => {} - MetaItem::NameValue(ref ident, ref lit) => { - if ident == "header" { - if let Lit::Str(ref name, _) = *lit { - return ResponseField::Header(name.clone(), field); - } else { - panic!("ruma_api! header attribute expects a string value"); + let response_fields = fields.into_iter().map(|mut field| { + let mut response_field_kind = ResponseFieldKind::Body; + + field.attrs = field.attrs.into_iter().filter(|attr| { + let (attr_ident, nested_meta_items) = match attr.value { + MetaItem::List(ref attr_ident, ref nested_meta_items) => { + (attr_ident, nested_meta_items) + } + _ => return true, + }; + + if attr_ident != "ruma_api" { + return true; + } + + for nested_meta_item in nested_meta_items { + match *nested_meta_item { + NestedMetaItem::MetaItem(ref meta_item) => { + match *meta_item { + MetaItem::Word(ref ident) => { + if ident == "header" { + response_field_kind = ResponseFieldKind::Header; + } else { + panic!( + "ruma_api! attribute meta item on responses must be: header" + ); + } + } + _ => panic!( + "ruma_api! attribute meta item on requests cannot be a list or name/value pair" + ), } } + NestedMetaItem::Literal(_) => panic!( + "ruma_api! attribute meta item on responses must be: header" + ), } } - } - return ResponseField::Body(field); + false + }).collect(); + + match response_field_kind { + ResponseFieldKind::Body => ResponseField::Body(field), + ResponseFieldKind::Header => ResponseField::Header(field), + } }).collect(); Response { @@ -88,7 +117,7 @@ impl ToTokens for Response { for response in self.fields.iter() { match *response { ResponseField::Body(ref field) => field.to_tokens(&mut tokens), - ResponseField::Header(_, ref field) => field.to_tokens(&mut tokens), + ResponseField::Header(ref field) => field.to_tokens(&mut tokens), } tokens.append(","); @@ -123,7 +152,7 @@ impl ToTokens for Response { #[derive(Debug)] pub enum ResponseField { Body(Field), - Header(String, Field), + Header(Field), } impl ResponseField { @@ -134,3 +163,8 @@ impl ResponseField { } } } + +enum ResponseFieldKind { + Body, + Header, +}