diff --git a/src/api.rs b/src/api.rs index 376e7b50..277818c7 100644 --- a/src/api.rs +++ b/src/api.rs @@ -54,7 +54,28 @@ impl ToTokens for Api { 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(); tokens.append(quote! { diff --git a/src/response.rs b/src/response.rs index 1bb14741..d3c7f434 100644 --- a/src/response.rs +++ b/src/response.rs @@ -38,15 +38,40 @@ impl Response { .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 } + + 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> for Response { fn from(fields: Vec) -> Self { + let mut has_newtype_body = false; + let response_fields = fields.into_iter().map(|mut field| { let mut response_field_kind = ResponseFieldKind::Body; @@ -67,7 +92,10 @@ impl From> for Response { NestedMetaItem::MetaItem(ref meta_item) => { match *meta_item { 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; } else { panic!( @@ -90,8 +118,15 @@ impl From> for Response { }).collect(); 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::NewtypeBody => ResponseField::NewtypeBody(field), } }).collect(); @@ -118,6 +153,7 @@ impl ToTokens for Response { match *response { ResponseField::Body(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(","); @@ -153,6 +189,7 @@ impl ToTokens for Response { pub enum ResponseField { Body(Field), Header(Field), + NewtypeBody(Field), } impl ResponseField { @@ -167,4 +204,5 @@ impl ResponseField { enum ResponseFieldKind { Body, Header, + NewtypeBody, }