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