diff --git a/Cargo.toml b/Cargo.toml index d1964b7b..f35ccca2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ features = ["full"] version = "0.11.11" [dev-dependencies] +futures = "0.1.13" serde = "1.0.4" serde_derive = "1.0.4" serde_json = "1.0.2" diff --git a/src/api.rs b/src/api.rs index 382e0eec..5efe2a9b 100644 --- a/src/api.rs +++ b/src/api.rs @@ -49,8 +49,34 @@ impl ToTokens for Api { Tokens::new() }; + let deserialize_response_body = if self.response.has_body_fields() { + quote! { + let bytes = hyper_response.body().fold::<_, _, Result<_, ::hyper::Error>>( + Vec::new(), + |mut bytes, chunk| { + bytes.write_all(&chunk).expect("failed to append body chunk"); + + Ok(bytes) + }).wait().expect("failed to read response body chunks into byte vector"); + + let response_body: ResponseBody = ::serde_json::from_slice(bytes.as_slice()) + .expect("failed to deserialize body"); + } + } else { + Tokens::new() + }; + + let response_init_fields = if self.response.has_fields() { + self.response.init_fields() + } else { + Tokens::new() + }; + tokens.append(quote! { use std::convert::TryFrom; + use std::io::Write; + + use ::futures::{Future, Stream}; /// The API endpoint. #[derive(Debug)] @@ -61,6 +87,7 @@ impl ToTokens for Api { impl TryFrom for ::hyper::Request { type Error = (); + #[allow(unused_mut, unused_variables)] fn try_from(request: Request) -> Result { let mut hyper_request = ::hyper::Request::new( ::hyper::#method, @@ -79,7 +106,13 @@ impl ToTokens for Api { type Error = (); fn try_from(hyper_response: ::hyper::Response) -> Result { - Ok(Response) + #deserialize_response_body + + let response = Response { + #response_init_fields + }; + + Ok(response) } } diff --git a/src/response.rs b/src/response.rs index 0f1b15b3..11067c35 100644 --- a/src/response.rs +++ b/src/response.rs @@ -10,6 +10,39 @@ impl Response { pub fn has_body_fields(&self) -> bool { self.fields.iter().any(|field| field.is_body()) } + + pub fn has_fields(&self) -> bool { + self.fields.len() != 0 + } + + pub fn init_fields(&self) -> Tokens { + let mut tokens = Tokens::new(); + + for response_field in self.fields.iter() { + match *response_field { + ResponseField::Body(ref field) => { + let field_name = field.ident.as_ref() + .expect("expected body field to have a name"); + + tokens.append(quote! { + #field_name: response_body.#field_name, + }); + } + ResponseField::Header(ref name, 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), + }); + } + } + } + + tokens + } } impl From> for Response { diff --git a/tests/ruma_api_macros.rs b/tests/ruma_api_macros.rs index 9364d28a..9b477386 100644 --- a/tests/ruma_api_macros.rs +++ b/tests/ruma_api_macros.rs @@ -1,10 +1,12 @@ #![feature(associated_consts, proc_macro, try_from)] +extern crate futures; extern crate hyper; extern crate ruma_api; extern crate ruma_api_macros; extern crate serde; #[macro_use] extern crate serde_derive; +extern crate serde_json; pub mod get_supported_versions { use ruma_api_macros::ruma_api;