Add newtype body field support for responses.

This commit is contained in:
Jimmy Cuadra 2017-05-21 01:52:16 -07:00
parent 58fab938b0
commit 35362e78a6
2 changed files with 62 additions and 3 deletions

View File

@ -54,7 +54,28 @@ impl ToTokens for Api {
Tokens::new() Tokens::new()
}; };
let deserialize_response_body = if self.response.has_body_fields() { let deserialize_response_body = if let Some(field) = self.response.newtype_body_field() {
let field_type = &field.ty;
let mut tokens = Tokens::new();
tokens.append(quote! {
let future_response = hyper_response.body()
.fold::<_, _, Result<_, ::std::io::Error>>(Vec::new(), |mut bytes, chunk| {
bytes.write_all(&chunk)?;
Ok(bytes)
})
.map_err(::ruma_api::Error::from)
.and_then(|bytes| {
::serde_json::from_slice::<#field_type>(bytes.as_slice())
.map_err(::ruma_api::Error::from)
})
});
tokens.append(".and_then(|response_body| {");
tokens
} else if self.response.has_body_fields() {
let mut tokens = Tokens::new(); let mut tokens = Tokens::new();
tokens.append(quote! { tokens.append(quote! {

View File

@ -38,15 +38,40 @@ impl Response {
.expect("missing expected request header: {}", #field_name), .expect("missing expected request header: {}", #field_name),
}); });
} }
ResponseField::NewtypeBody(ref field) => {
let field_name = field.ident.as_ref()
.expect("expected body field to have a name");
tokens.append(quote! {
#field_name: response_body,
});
}
} }
} }
tokens tokens
} }
pub fn newtype_body_field(&self) -> Option<&Field> {
for response_field in self.fields.iter() {
match *response_field {
ResponseField::NewtypeBody(ref field) => {
return Some(field);
}
_ => continue,
}
}
None
}
} }
impl From<Vec<Field>> for Response { impl From<Vec<Field>> for Response {
fn from(fields: Vec<Field>) -> Self { fn from(fields: Vec<Field>) -> Self {
let mut has_newtype_body = false;
let response_fields = fields.into_iter().map(|mut field| { let response_fields = fields.into_iter().map(|mut field| {
let mut response_field_kind = ResponseFieldKind::Body; let mut response_field_kind = ResponseFieldKind::Body;
@ -67,7 +92,10 @@ impl From<Vec<Field>> for Response {
NestedMetaItem::MetaItem(ref meta_item) => { NestedMetaItem::MetaItem(ref meta_item) => {
match *meta_item { match *meta_item {
MetaItem::Word(ref ident) => { MetaItem::Word(ref ident) => {
if ident == "header" { if ident == "body" {
has_newtype_body = true;
response_field_kind = ResponseFieldKind::NewtypeBody;
} else if ident == "header" {
response_field_kind = ResponseFieldKind::Header; response_field_kind = ResponseFieldKind::Header;
} else { } else {
panic!( panic!(
@ -90,8 +118,15 @@ impl From<Vec<Field>> for Response {
}).collect(); }).collect();
match response_field_kind { match response_field_kind {
ResponseFieldKind::Body => ResponseField::Body(field), ResponseFieldKind::Body => {
if has_newtype_body {
panic!("ruma_api! responses cannot have both normal body fields and a newtype body field");
} else {
return ResponseField::Body(field);
}
}
ResponseFieldKind::Header => ResponseField::Header(field), ResponseFieldKind::Header => ResponseField::Header(field),
ResponseFieldKind::NewtypeBody => ResponseField::NewtypeBody(field),
} }
}).collect(); }).collect();
@ -118,6 +153,7 @@ impl ToTokens for Response {
match *response { match *response {
ResponseField::Body(ref field) => field.to_tokens(&mut tokens), 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),
ResponseField::NewtypeBody(ref field) => field.to_tokens(&mut tokens),
} }
tokens.append(","); tokens.append(",");
@ -153,6 +189,7 @@ impl ToTokens for Response {
pub enum ResponseField { pub enum ResponseField {
Body(Field), Body(Field),
Header(Field), Header(Field),
NewtypeBody(Field),
} }
impl ResponseField { impl ResponseField {
@ -167,4 +204,5 @@ impl ResponseField {
enum ResponseFieldKind { enum ResponseFieldKind {
Body, Body,
Header, Header,
NewtypeBody,
} }