Simplify ruma-api-macros codegen

This commit is contained in:
Jonas Platte 2019-11-28 21:52:48 +01:00
parent 3696516679
commit 81207890b6
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
3 changed files with 73 additions and 197 deletions

View File

@ -108,7 +108,7 @@ impl ToTokens for Api {
TokenStream::new()
};
let (set_request_path, parse_request_path) = if self.request.has_path_fields() {
let (url_set_path, parse_request_path) = if self.request.has_path_fields() {
let path_str = path.value();
assert!(path_str.starts_with('/'), "path needs to start with '/'");
@ -182,7 +182,7 @@ impl ToTokens for Api {
(set_tokens, parse_tokens)
};
let set_request_query = if let Some(field) = self.request.query_map_field() {
let url_set_querystring = if let Some(field) = self.request.query_map_field() {
let field_name = field.ident.as_ref().expect("expected field to have identifier");
let field_type = &field.ty;
@ -252,10 +252,8 @@ impl ToTokens for Api {
quote! {
#field_name: request_query
}
} else if self.request.has_query_fields() {
self.request.request_init_query_fields()
} else {
TokenStream::new()
self.request.request_init_query_fields()
};
let add_headers_to_request = if self.request.has_header_fields() {
@ -282,76 +280,22 @@ impl ToTokens for Api {
TokenStream::new()
};
let create_http_request = if let Some(field) = self.request.newtype_body_field() {
let request_body_initializers = if let Some(field) = self.request.newtype_body_field() {
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
quote! {
let request_body = RequestBody(request.#field_name);
let mut http_request = ruma_api::exports::http::Request::new(
ruma_api::exports::serde_json::to_vec(&request_body)?,
);
}
} else if self.request.has_body_fields() {
let request_body_init_fields = self.request.request_body_init_fields();
quote! {
let request_body = RequestBody {
#request_body_init_fields
};
let mut http_request = ruma_api::exports::http::Request::new(
ruma_api::exports::serde_json::to_vec(&request_body)?,
);
}
quote! { (request.#field_name) }
} else {
quote! {
let mut http_request = ruma_api::exports::http::Request::new(Vec::new());
}
};
let extract_request_body = if self.request.newtype_body_field().is_some() {
quote! {
let request_body =
ruma_api::exports::serde_json::from_slice(request.body().as_slice())?;
}
} else if self.request.has_body_fields() {
quote! {
let request_body: <RequestBody as ruma_api::Outgoing>::Incoming =
ruma_api::exports::serde_json::from_slice(request.body().as_slice())?;
}
} else {
TokenStream::new()
let initializers = self.request.request_body_init_fields();
quote! { { #initializers } }
};
let parse_request_body = if let Some(field) = self.request.newtype_body_field() {
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
quote! {
#field_name: request_body,
#field_name: request_body.0,
}
} else if self.request.has_body_fields() {
} else {
self.request.request_init_body_fields()
} else {
TokenStream::new()
};
let response_body_type_annotation = if self.response.has_body_fields() {
quote!(: <ResponseBody as ruma_api::Outgoing>::Incoming)
} else {
TokenStream::new()
};
let try_deserialize_response_body = if self.response.has_body() {
quote! {
ruma_api::exports::serde_json::from_slice(
http_response.into_body().as_slice(),
)?
}
} else {
quote! {
()
}
};
let extract_response_headers = if self.response.has_header_fields() {
@ -362,24 +306,11 @@ impl ToTokens for Api {
TokenStream::new()
};
let response_init_fields = if self.response.has_fields() {
self.response.init_fields()
} else {
TokenStream::new()
};
let response_init_fields = self.response.init_fields();
let serialize_response_headers = self.response.apply_header_fields();
let try_serialize_response_body = if self.response.has_body() {
let body = self.response.to_body();
quote! {
ruma_api::exports::serde_json::to_vec(&#body)?
}
} else {
quote! {
"{}".as_bytes().to_vec()
}
};
let body = self.response.to_body();
let request_doc = format!(
"Data for a request to the `{}` API endpoint.\n\n{}",
@ -406,7 +337,9 @@ impl ToTokens for Api {
#extract_request_path
#extract_request_query
#extract_request_headers
#extract_request_body
let request_body: <RequestBody as ruma_api::Outgoing>::Incoming =
ruma_api::exports::serde_json::from_slice(request.body().as_slice())?;
Ok(Self {
#parse_request_path
@ -431,10 +364,14 @@ impl ToTokens for Api {
ruma_api::exports::url::Url::parse("http://invalid-host-please-change/")
.unwrap();
{ #set_request_path }
{ #set_request_query }
{ #url_set_path }
{ #url_set_querystring }
#create_http_request
let request_body = RequestBody #request_body_initializers;
let mut http_request = ruma_api::exports::http::Request::new(
ruma_api::exports::serde_json::to_vec(&request_body)?,
);
*http_request.method_mut() = ruma_api::exports::http::Method::#method;
*http_request.uri_mut() = url.into_string().parse().unwrap();
@ -456,7 +393,7 @@ impl ToTokens for Api {
let response = ruma_api::exports::http::Response::builder()
.header(ruma_api::exports::http::header::CONTENT_TYPE, "application/json")
#serialize_response_headers
.body(#try_serialize_response_body)
.body(ruma_api::exports::serde_json::to_vec(&#body)?)
.unwrap();
Ok(response)
}
@ -472,8 +409,10 @@ impl ToTokens for Api {
if http_response.status().is_success() {
#extract_response_headers
let response_body #response_body_type_annotation =
#try_deserialize_response_body;
let response_body: <ResponseBody as ruma_api::Outgoing>::Incoming =
ruma_api::exports::serde_json::from_slice(
http_response.into_body().as_slice(),
)?;
Ok(Self {
#response_init_fields

View File

@ -168,9 +168,7 @@ impl Request {
})
});
quote! {
#(#fields,)*
}
quote! { #(#fields,)* }
}
}
@ -293,46 +291,24 @@ impl TryFrom<RawRequest> for Request {
impl ToTokens for Request {
fn to_tokens(&self, tokens: &mut TokenStream) {
let request_struct_header = quote! {
#[derive(Debug, Clone, ruma_api::Outgoing)]
#[incoming_no_deserialize]
pub struct Request
};
let request_struct_body = if self.fields.is_empty() {
let request_def = if self.fields.is_empty() {
quote!(;)
} else {
let fields =
self.fields.iter().map(|request_field| strip_serde_attrs(request_field.field()));
quote! {
{
#(#fields),*
}
}
quote! { { #(#fields),* } }
};
let request_body_struct =
let (derive_deserialize, request_body_def) =
if let Some(body_field) = self.fields.iter().find(|f| f.is_newtype_body()) {
let field = body_field.field();
let ty = &field.ty;
let span = field.span();
let field = Field { ident: None, colon_token: None, ..body_field.field().clone() };
let derive_deserialize = if body_field.has_wrap_incoming_attr() {
TokenStream::new()
} else {
quote!(ruma_api::exports::serde::Deserialize)
};
quote_spanned! {span=>
/// Data in the request body.
#[derive(
Debug,
ruma_api::Outgoing,
ruma_api::exports::serde::Serialize,
#derive_deserialize
)]
struct RequestBody(#ty);
}
(derive_deserialize, quote! { (#field); })
} else if self.has_body_fields() {
let fields = self.fields.iter().filter(|f| f.is_body());
let derive_deserialize = if fields.clone().any(|f| f.has_wrap_incoming_attr()) {
@ -342,20 +318,9 @@ impl ToTokens for Request {
};
let fields = fields.map(RequestField::field);
quote! {
/// Data in the request body.
#[derive(
Debug,
ruma_api::Outgoing,
ruma_api::exports::serde::Serialize,
#derive_deserialize
)]
struct RequestBody {
#(#fields),*
}
}
(derive_deserialize, quote! { { #(#fields),* } })
} else {
TokenStream::new()
(quote!(ruma_api::exports::serde::Deserialize), quote!(;))
};
let request_path_struct = if self.has_path_fields() {
@ -376,18 +341,17 @@ impl ToTokens for Request {
TokenStream::new()
};
let request_query_struct = if let Some(field) = self.query_map_field() {
let ty = &field.ty;
let span = field.span();
let request_query_struct = if let Some(f) = self.query_map_field() {
let field = Field { ident: None, colon_token: None, ..f.clone() };
quote_spanned! {span=>
quote! {
/// Data in the request's query string.
#[derive(
Debug,
ruma_api::exports::serde::Deserialize,
ruma_api::exports::serde::Serialize,
)]
struct RequestQuery(#ty);
struct RequestQuery(#field);
}
} else if self.has_query_fields() {
let fields = self.fields.iter().filter_map(RequestField::as_query_field);
@ -408,9 +372,19 @@ impl ToTokens for Request {
};
let request = quote! {
#request_struct_header
#request_struct_body
#request_body_struct
#[derive(Debug, Clone, ruma_api::Outgoing)]
#[incoming_no_deserialize]
pub struct Request #request_def
/// Data in the request body.
#[derive(
Debug,
ruma_api::Outgoing,
ruma_api::exports::serde::Serialize,
#derive_deserialize
)]
struct RequestBody #request_body_def
#request_path_struct
#request_query_struct
};

View File

@ -23,21 +23,11 @@ impl Response {
self.fields.iter().any(|field| field.is_body())
}
/// Whether or not this response has any fields.
pub fn has_fields(&self) -> bool {
!self.fields.is_empty()
}
/// Whether or not this response has any data in HTTP headers.
pub fn has_header_fields(&self) -> bool {
self.fields.iter().any(|field| field.is_header())
}
/// Whether or not this response has any data in the HTTP body.
pub fn has_body(&self) -> bool {
self.fields.iter().any(|field| !field.is_header())
}
/// Whether any field has a #[wrap_incoming] attribute.
pub fn uses_wrap_incoming(&self) -> bool {
self.fields.iter().any(|f| f.has_wrap_incoming_attr())
@ -74,7 +64,7 @@ impl Response {
let span = field.span();
quote_spanned! {span=>
#field_name: response_body
#field_name: response_body.0
}
}
});
@ -100,9 +90,7 @@ impl Response {
}
});
quote! {
#(#header_calls)*
}
quote! { #(#header_calls)* }
}
/// Produces code to initialize the struct that will be used to create the response body.
@ -127,9 +115,7 @@ impl Response {
});
quote! {
ResponseBody {
#(#fields),*
}
ResponseBody { #(#fields),* }
}
}
}
@ -231,46 +217,25 @@ impl TryFrom<RawResponse> for Response {
impl ToTokens for Response {
fn to_tokens(&self, tokens: &mut TokenStream) {
let response_struct_header = quote! {
#[derive(Debug, Clone, ruma_api::Outgoing)]
#[incoming_no_deserialize]
pub struct Response
};
let response_struct_body = if self.fields.is_empty() {
let response_def = if self.fields.is_empty() {
quote!(;)
} else {
let fields =
self.fields.iter().map(|response_field| strip_serde_attrs(response_field.field()));
quote! {
{
#(#fields),*
}
}
quote! { { #(#fields),* } }
};
let response_body_struct =
let (derive_deserialize, response_body_def) =
if let Some(body_field) = self.fields.iter().find(|f| f.is_newtype_body()) {
let field = body_field.field();
let ty = &field.ty;
let span = field.span();
let field = Field { ident: None, colon_token: None, ..body_field.field().clone() };
let derive_deserialize = if body_field.has_wrap_incoming_attr() {
TokenStream::new()
} else {
quote!(ruma_api::exports::serde::Deserialize)
};
quote_spanned! {span=>
/// Data in the response body.
#[derive(
Debug,
ruma_api::Outgoing,
ruma_api::exports::serde::Serialize,
#derive_deserialize
)]
struct ResponseBody(#ty);
}
(derive_deserialize, quote! { (#field); })
} else if self.has_body_fields() {
let fields = self.fields.iter().filter(|f| f.is_body());
let derive_deserialize = if fields.clone().any(|f| f.has_wrap_incoming_attr()) {
@ -280,26 +245,24 @@ impl ToTokens for Response {
};
let fields = fields.map(ResponseField::field);
quote! {
/// Data in the response body.
#[derive(
Debug,
ruma_api::Outgoing,
ruma_api::exports::serde::Serialize,
#derive_deserialize
)]
struct ResponseBody {
#(#fields),*
}
}
(derive_deserialize, quote!({ #(#fields),* }))
} else {
TokenStream::new()
(quote!(ruma_api::exports::serde::Deserialize), quote!(;))
};
let response = quote! {
#response_struct_header
#response_struct_body
#response_body_struct
#[derive(Debug, Clone, ruma_api::Outgoing)]
#[incoming_no_deserialize]
pub struct Response #response_def
/// Data in the response body.
#[derive(
Debug,
ruma_api::Outgoing,
ruma_api::exports::serde::Serialize,
#derive_deserialize
)]
struct ResponseBody #response_body_def
};
response.to_tokens(tokens);