Update request/response header logic for new style.
This commit is contained in:
		
							parent
							
								
									f0f4f9bd17
								
							
						
					
					
						commit
						c9454caff1
					
				| @ -10,7 +10,7 @@ You define the endpoint's metadata, request fields, and response fields, and the | ||||
| Here is an example that shows most of the macro's functionality. | ||||
| 
 | ||||
| ``` rust | ||||
| #![feature(associated_consts, proc_macro, try_from)] | ||||
| #![feature(proc_macro, try_from)] | ||||
| 
 | ||||
| extern crate futures; | ||||
| extern crate http; | ||||
|  | ||||
| @ -99,7 +99,7 @@ impl ToTokens for Api { | ||||
|                     }); | ||||
|                 } else { | ||||
|                     tokens.append_all(quote! { | ||||
|                         ("#segment"); | ||||
|                         (#segment); | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
| @ -125,6 +125,18 @@ impl ToTokens for Api { | ||||
|             Tokens::new() | ||||
|         }; | ||||
| 
 | ||||
|         let add_headers_to_request = if self.request.has_header_fields() { | ||||
|             let mut header_tokens = quote! { | ||||
|                 let headers = http_request.headers_mut(); | ||||
|             }; | ||||
| 
 | ||||
|             header_tokens.append_all(self.request.add_headers_to_request()); | ||||
| 
 | ||||
|             header_tokens | ||||
|         } else { | ||||
|             Tokens::new() | ||||
|         }; | ||||
| 
 | ||||
|         let add_body_to_request = if let Some(field) = self.request.newtype_body_field() { | ||||
|             let field_name = field.ident.expect("expected field to have an identifier"); | ||||
| 
 | ||||
| @ -211,7 +223,7 @@ impl ToTokens for Api { | ||||
| 
 | ||||
|             #request_types | ||||
| 
 | ||||
|             impl ::std::convert::TryFrom<Request> for ::http::Request { | ||||
|             impl<T> ::std::convert::TryFrom<Request> for ::http::Request<T> { | ||||
|                 type Error = ::ruma_api::Error; | ||||
| 
 | ||||
|                 #[allow(unused_mut, unused_variables)] | ||||
| @ -232,6 +244,8 @@ impl ToTokens for Api { | ||||
|                         url.into_string().parse().unwrap(), | ||||
|                     ); | ||||
| 
 | ||||
|                     { #add_headers_to_request } | ||||
| 
 | ||||
|                     { #add_body_to_request } | ||||
| 
 | ||||
|                     Ok(http_request) | ||||
| @ -240,12 +254,12 @@ impl ToTokens for Api { | ||||
| 
 | ||||
|             #response_types | ||||
| 
 | ||||
|             impl ::futures::future::FutureFrom<::http::Response> for Response { | ||||
|             impl<T> ::futures::future::FutureFrom<::http::Response<T>> for Response { | ||||
|                 type Future = Box<_Future<Item = Self, Error = Self::Error>>; | ||||
|                 type Error = ::ruma_api::Error; | ||||
| 
 | ||||
|                 #[allow(unused_variables)] | ||||
|                 fn future_from(http_response: ::http::Response) | ||||
|                 fn future_from(http_response: ::http::Response<T>) | ||||
|                 -> Box<_Future<Item = Self, Error = Self::Error>> { | ||||
|                     #extract_headers | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| use quote::{ToTokens, Tokens}; | ||||
| use syn::spanned::Spanned; | ||||
| use syn::{Field, Meta, NestedMeta}; | ||||
| use syn::{Field, Ident, Lit, Meta, NestedMeta}; | ||||
| 
 | ||||
| use api::strip_serde_attrs; | ||||
| 
 | ||||
| @ -9,10 +9,31 @@ pub struct Request { | ||||
| } | ||||
| 
 | ||||
| impl Request { | ||||
|     pub fn add_headers_to_request(&self) -> Tokens { | ||||
|         self.header_fields().fold(Tokens::new(), |mut header_tokens, request_field| { | ||||
|             let (field, header_name_string) = match request_field { | ||||
|                 RequestField::Header(field, header_name_string) => (field, header_name_string), | ||||
|                 _ => panic!("expected request field to be header variant"), | ||||
|             }; | ||||
| 
 | ||||
|             let field_name = &field.ident; | ||||
|             let header_name = Ident::from(header_name_string.as_ref()); | ||||
| 
 | ||||
|             header_tokens.append_all(quote! { | ||||
|                 headers.append(::http::header::#header_name, request.#field_name); | ||||
|             }); | ||||
| 
 | ||||
|             header_tokens | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn has_body_fields(&self) -> bool { | ||||
|         self.fields.iter().any(|field| field.is_body()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn has_header_fields(&self) -> bool { | ||||
|         self.fields.iter().any(|field| field.is_header()) | ||||
|     } | ||||
|     pub fn has_path_fields(&self) -> bool { | ||||
|         self.fields.iter().any(|field| field.is_path()) | ||||
|     } | ||||
| @ -21,6 +42,10 @@ impl Request { | ||||
|         self.fields.iter().any(|field| field.is_query()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn header_fields(&self) -> impl Iterator<Item = &RequestField> { | ||||
|         self.fields.iter().filter(|field| field.is_header()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn path_field_count(&self) -> usize { | ||||
|         self.fields.iter().filter(|field| field.is_path()).count() | ||||
|     } | ||||
| @ -72,6 +97,7 @@ impl From<Vec<Field>> for Request { | ||||
| 
 | ||||
|         let fields = fields.into_iter().map(|mut field| { | ||||
|             let mut field_kind = RequestFieldKind::Body; | ||||
|             let mut header = None; | ||||
| 
 | ||||
|             field.attrs = field.attrs.into_iter().filter(|attr| { | ||||
|                 let meta = attr.interpret_meta() | ||||
| @ -103,7 +129,14 @@ impl From<Vec<Field>> for Request { | ||||
|                                 } | ||||
|                                 Meta::NameValue(name_value) => { | ||||
|                                     match name_value.ident.as_ref() { | ||||
|                                         "header" => field_kind = RequestFieldKind::Header, | ||||
|                                         "header" => { | ||||
|                                             match name_value.lit { | ||||
|                                                 Lit::Str(lit_str) => header = Some(lit_str.value()), | ||||
|                                                 _ => panic!("ruma_api! header attribute's value must be a string literal"), | ||||
|                                             } | ||||
| 
 | ||||
|                                             field_kind = RequestFieldKind::Header; | ||||
|                                         } | ||||
|                                         _ => panic!("ruma_api! name/value pair attribute on requests must be: header"), | ||||
|                                     } | ||||
|                                 } | ||||
| @ -126,7 +159,7 @@ impl From<Vec<Field>> for Request { | ||||
|                 ); | ||||
|             } | ||||
| 
 | ||||
|             RequestField::new(field_kind, field) | ||||
|             RequestField::new(field_kind, field, header) | ||||
|         }).collect(); | ||||
| 
 | ||||
|         Request { | ||||
| @ -267,17 +300,17 @@ impl ToTokens for Request { | ||||
| 
 | ||||
| pub enum RequestField { | ||||
|     Body(Field), | ||||
|     Header(Field), | ||||
|     Header(Field, String), | ||||
|     NewtypeBody(Field), | ||||
|     Path(Field), | ||||
|     Query(Field), | ||||
| } | ||||
| 
 | ||||
| impl RequestField { | ||||
|     fn new(kind: RequestFieldKind, field: Field) -> RequestField { | ||||
|     fn new(kind: RequestFieldKind, field: Field, header: Option<String>) -> RequestField { | ||||
|         match kind { | ||||
|             RequestFieldKind::Body => RequestField::Body(field), | ||||
|             RequestFieldKind::Header => RequestField::Header(field), | ||||
|             RequestFieldKind::Header => RequestField::Header(field, header.expect("missing header name")), | ||||
|             RequestFieldKind::NewtypeBody => RequestField::NewtypeBody(field), | ||||
|             RequestFieldKind::Path => RequestField::Path(field), | ||||
|             RequestFieldKind::Query => RequestField::Query(field), | ||||
| @ -286,11 +319,11 @@ impl RequestField { | ||||
| 
 | ||||
|     fn kind(&self) -> RequestFieldKind { | ||||
|         match *self { | ||||
|             RequestField::Body(_) => RequestFieldKind::Body, | ||||
|             RequestField::Header(_) => RequestFieldKind::Header, | ||||
|             RequestField::NewtypeBody(_) => RequestFieldKind::NewtypeBody, | ||||
|             RequestField::Path(_) => RequestFieldKind::Path, | ||||
|             RequestField::Query(_) => RequestFieldKind::Query, | ||||
|             RequestField::Body(..) => RequestFieldKind::Body, | ||||
|             RequestField::Header(..) => RequestFieldKind::Header, | ||||
|             RequestField::NewtypeBody(..) => RequestFieldKind::NewtypeBody, | ||||
|             RequestField::Path(..) => RequestFieldKind::Path, | ||||
|             RequestField::Query(..) => RequestFieldKind::Query, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -298,6 +331,10 @@ impl RequestField { | ||||
|         self.kind() == RequestFieldKind::Body | ||||
|     } | ||||
| 
 | ||||
|     fn is_header(&self) -> bool { | ||||
|         self.kind() == RequestFieldKind::Header | ||||
|     } | ||||
| 
 | ||||
|     fn is_path(&self) -> bool { | ||||
|         self.kind() == RequestFieldKind::Path | ||||
|     } | ||||
| @ -309,7 +346,7 @@ impl RequestField { | ||||
|     fn field(&self) -> &Field { | ||||
|         match *self { | ||||
|             RequestField::Body(ref field) => field, | ||||
|             RequestField::Header(ref field) => field, | ||||
|             RequestField::Header(ref field, _) => field, | ||||
|             RequestField::NewtypeBody(ref field) => field, | ||||
|             RequestField::Path(ref field) => field, | ||||
|             RequestField::Query(ref field) => field, | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| use quote::{ToTokens, Tokens}; | ||||
| use syn::spanned::Spanned; | ||||
| use syn::{Field, Meta, NestedMeta}; | ||||
| use syn::{Field, Ident, Lit, Meta, NestedMeta}; | ||||
| 
 | ||||
| use api::strip_serde_attrs; | ||||
| 
 | ||||
| @ -34,13 +34,13 @@ impl Response { | ||||
|                         #field_name: response_body.#field_name, | ||||
|                     }); | ||||
|                 } | ||||
|                 ResponseField::Header(ref field) => { | ||||
|                 ResponseField::Header(ref field, ref header) => { | ||||
|                     let field_name = field.ident.expect("expected field to have an identifier"); | ||||
|                     let field_type = &field.ty; | ||||
|                     let header_name = Ident::from(header.as_ref()); | ||||
|                     let span = field.span(); | ||||
| 
 | ||||
|                     tokens.append_all(quote_spanned! {span=> | ||||
|                         #field_name: headers.remove::<#field_type>() | ||||
|                         #field_name: headers.remove(::http::header::#header_name) | ||||
|                             .expect("missing expected request header"), | ||||
|                     }); | ||||
|                 } | ||||
| @ -80,6 +80,7 @@ impl From<Vec<Field>> for Response { | ||||
| 
 | ||||
|         let fields = fields.into_iter().map(|mut field| { | ||||
|             let mut field_kind = ResponseFieldKind::Body; | ||||
|             let mut header = None; | ||||
| 
 | ||||
|             field.attrs = field.attrs.into_iter().filter(|attr| { | ||||
|                 let meta = attr.interpret_meta() | ||||
| @ -109,7 +110,14 @@ impl From<Vec<Field>> for Response { | ||||
|                                 } | ||||
|                                 Meta::NameValue(name_value) => { | ||||
|                                     match name_value.ident.as_ref() { | ||||
|                                         "header" => field_kind = ResponseFieldKind::Header, | ||||
|                                         "header" => { | ||||
|                                             match name_value.lit { | ||||
|                                                 Lit::Str(lit_str) => header = Some(lit_str.value()), | ||||
|                                                 _ => panic!("ruma_api! header attribute's value must be a string literal"), | ||||
|                                             } | ||||
| 
 | ||||
|                                             field_kind = ResponseFieldKind::Header; | ||||
|                                         } | ||||
|                                         _ => panic!("ruma_api! name/value pair attribute on requests must be: header"), | ||||
|                                     } | ||||
|                                 } | ||||
| @ -133,7 +141,7 @@ impl From<Vec<Field>> for Response { | ||||
|                         return ResponseField::Body(field); | ||||
|                     } | ||||
|                 } | ||||
|                 ResponseFieldKind::Header => ResponseField::Header(field), | ||||
|                 ResponseFieldKind::Header => ResponseField::Header(field, header.expect("missing header name")), | ||||
|                 ResponseFieldKind::NewtypeBody => ResponseField::NewtypeBody(field), | ||||
|             } | ||||
|         }).collect(); | ||||
| @ -220,7 +228,7 @@ impl ToTokens for Response { | ||||
| 
 | ||||
| pub enum ResponseField { | ||||
|     Body(Field), | ||||
|     Header(Field), | ||||
|     Header(Field, String), | ||||
|     NewtypeBody(Field), | ||||
| } | ||||
| 
 | ||||
| @ -228,21 +236,21 @@ impl ResponseField { | ||||
|     fn field(&self) -> &Field { | ||||
|         match *self { | ||||
|             ResponseField::Body(ref field) => field, | ||||
|             ResponseField::Header(ref field) => field, | ||||
|             ResponseField::Header(ref field, _) => field, | ||||
|             ResponseField::NewtypeBody(ref field) => field, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn is_body(&self) -> bool { | ||||
|         match *self { | ||||
|             ResponseField::Body(_) => true, | ||||
|             ResponseField::Body(..) => true, | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn is_header(&self) -> bool { | ||||
|         match *self { | ||||
|             ResponseField::Header(_) => true, | ||||
|             ResponseField::Header(..) => true, | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #![feature(associated_consts, proc_macro, try_from)] | ||||
| #![feature(proc_macro, try_from)] | ||||
| 
 | ||||
| extern crate futures; | ||||
| extern crate http; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user