Get rid of almost all calls to append_all

This commit is contained in:
Jonas Platte 2018-12-15 21:22:07 +01:00
parent 0e494ade66
commit 0a4239b678
3 changed files with 144 additions and 142 deletions

View File

@ -82,7 +82,22 @@ impl ToTokens for Api {
let request_path_init_fields = self.request.request_path_init_fields(); let request_path_init_fields = self.request.request_path_init_fields();
let mut set_tokens = quote! { let path_segments = path_str[1..].split('/').into_iter();
let path_segment_push = path_segments.clone().map(|segment| {
let arg = if segment.starts_with(':') {
let path_var = &segment[1..];
let path_var_ident = Ident::new(path_var, Span::call_site());
quote!(&request_path.#path_var_ident.to_string())
} else {
quote!(#segment)
};
quote! {
path_segments.push(#arg);
}
});
let set_tokens = quote! {
let request_path = RequestPath { let request_path = RequestPath {
#request_path_init_fields #request_path_init_fields
}; };
@ -91,28 +106,22 @@ impl ToTokens for Api {
// cannot-be-base url like `mailto:` or `data:`, which is not // cannot-be-base url like `mailto:` or `data:`, which is not
// the case for our placeholder url. // the case for our placeholder url.
let mut path_segments = url.path_segments_mut().unwrap(); let mut path_segments = url.path_segments_mut().unwrap();
#(#path_segment_push)*
}; };
let mut parse_tokens = TokenStream::new(); let path_fields = path_segments
.enumerate()
for (i, segment) in path_str[1..].split('/').into_iter().enumerate() { .filter(|(_, s)| s.starts_with(':'))
set_tokens.append_all(quote! { .map(|(i, segment)| {
path_segments.push
});
if segment.starts_with(':') {
let path_var = &segment[1..]; let path_var = &segment[1..];
let path_var_ident = Ident::new(path_var, Span::call_site()); let path_var_ident = Ident::new(path_var, Span::call_site());
let path_field = self
set_tokens.append_all(quote! { .request
(&request_path.#path_var_ident.to_string()); .path_field(path_var)
});
let path_field = self.request.path_field(path_var)
.expect("expected request to have path field"); .expect("expected request to have path field");
let ty = &path_field.ty; let ty = &path_field.ty;
parse_tokens.append_all(quote! { quote! {
#path_var_ident: { #path_var_ident: {
let segment = path_segments.get(#i).unwrap().as_bytes(); let segment = path_segments.get(#i).unwrap().as_bytes();
let decoded = let decoded =
@ -120,14 +129,13 @@ impl ToTokens for Api {
.decode_utf8_lossy(); .decode_utf8_lossy();
#ty::deserialize(decoded.into_deserializer()) #ty::deserialize(decoded.into_deserializer())
.map_err(|e: ::serde_json::error::Error| e)? .map_err(|e: ::serde_json::error::Error| e)?
}, }
}); }
} else { });
set_tokens.append_all(quote! {
(#segment); let parse_tokens = quote! {
}); #(#path_fields,)*
} };
}
(set_tokens, parse_tokens) (set_tokens, parse_tokens)
} else { } else {
@ -168,13 +176,11 @@ impl ToTokens for Api {
}; };
let add_headers_to_request = if self.request.has_header_fields() { let add_headers_to_request = if self.request.has_header_fields() {
let mut header_tokens = quote! { let add_headers = self.request.add_headers_to_request();
quote! {
let headers = http_request.headers_mut(); let headers = http_request.headers_mut();
}; #add_headers
}
header_tokens.append_all(self.request.add_headers_to_request());
header_tokens
} else { } else {
TokenStream::new() TokenStream::new()
}; };

View File

@ -11,7 +11,7 @@ pub struct Request {
impl Request { impl Request {
pub fn add_headers_to_request(&self) -> TokenStream { pub fn add_headers_to_request(&self) -> TokenStream {
self.header_fields().fold(TokenStream::new(), |mut header_tokens, request_field| { let append_stmts = self.header_fields().map(|request_field| {
let (field, header_name_string) = match request_field { let (field, header_name_string) = match request_field {
RequestField::Header(field, header_name_string) => (field, header_name_string), RequestField::Header(field, header_name_string) => (field, header_name_string),
_ => panic!("expected request field to be header variant"), _ => panic!("expected request field to be header variant"),
@ -20,20 +20,22 @@ impl Request {
let field_name = &field.ident; let field_name = &field.ident;
let header_name = Ident::new(header_name_string.as_ref(), Span::call_site()); let header_name = Ident::new(header_name_string.as_ref(), Span::call_site());
header_tokens.append_all(quote! { quote! {
headers.append( headers.append(
::http::header::#header_name, ::http::header::#header_name,
::http::header::HeaderValue::from_str(request.#field_name.as_ref()) ::http::header::HeaderValue::from_str(request.#field_name.as_ref())
.expect("failed to convert value into HeaderValue"), .expect("failed to convert value into HeaderValue"),
); );
}); }
});
header_tokens quote! {
}) #(#append_stmts)*
}
} }
pub fn parse_headers_from_request(&self) -> TokenStream { pub fn parse_headers_from_request(&self) -> TokenStream {
self.header_fields().fold(TokenStream::new(), |mut header_tokens, request_field| { let fields = self.header_fields().map(|request_field| {
let (field, header_name_string) = match request_field { let (field, header_name_string) = match request_field {
RequestField::Header(field, header_name_string) => (field, header_name_string), RequestField::Header(field, header_name_string) => (field, header_name_string),
_ => panic!("expected request field to be header variant"), _ => panic!("expected request field to be header variant"),
@ -42,15 +44,17 @@ impl Request {
let field_name = &field.ident; let field_name = &field.ident;
let header_name = Ident::new(header_name_string.as_ref(), Span::call_site()); let header_name = Ident::new(header_name_string.as_ref(), Span::call_site());
header_tokens.append_all(quote! { quote! {
#field_name: headers.get(::http::header::#header_name) #field_name: headers.get(::http::header::#header_name)
.and_then(|v| v.to_str().ok()) .and_then(|v| v.to_str().ok())
.ok_or(::serde_json::Error::missing_field(#header_name_string))? .ok_or(::serde_json::Error::missing_field(#header_name_string))?
.to_owned(), .to_owned()
}); }
});
header_tokens quote! {
}) #(#fields,)*
}
} }
pub fn has_body_fields(&self) -> bool { pub fn has_body_fields(&self) -> bool {
@ -120,19 +124,28 @@ impl Request {
self.struct_init_fields(RequestFieldKind::Query, quote!(request_query)) self.struct_init_fields(RequestFieldKind::Query, quote!(request_query))
} }
fn struct_init_fields(&self, request_field_kind: RequestFieldKind, src: TokenStream) -> TokenStream { fn struct_init_fields(
let mut tokens = TokenStream::new(); &self,
request_field_kind: RequestFieldKind,
src: TokenStream,
) -> TokenStream {
let fields = self.fields.iter().filter_map(|f| {
f.field_(request_field_kind).map(|field| {
let field_name = field
.ident
.as_ref()
.expect("expected field to have an identifier");
let span = field.span();
for field in self.fields.iter().flat_map(|f| f.field_(request_field_kind)) { quote_spanned! {span=>
let field_name = field.ident.as_ref().expect("expected field to have an identifier"); #field_name: #src.#field_name
let span = field.span(); }
})
});
tokens.append_all(quote_spanned! {span=> quote! {
#field_name: #src.#field_name, #(#fields,)*
});
} }
tokens
} }
} }
@ -224,114 +237,98 @@ impl ToTokens for Request {
let request_struct_body = if self.fields.is_empty() { let request_struct_body = if self.fields.is_empty() {
quote!(;) quote!(;)
} else { } else {
let fields = self.fields.iter().fold(TokenStream::new(), |mut field_tokens, request_field| { let fields = self.fields.iter().map(|request_field| {
let field = request_field.field(); let field = request_field.field();
let span = field.span(); let span = field.span();
let stripped_field = strip_serde_attrs(field); let stripped_field = strip_serde_attrs(field);
field_tokens.append_all(quote_spanned!(span=> #stripped_field,)); quote_spanned!(span=> #stripped_field)
field_tokens
}); });
quote! { quote! {
{ {
#fields #(#fields),*
} }
} }
}; };
let request_body_struct; let request_body_struct = if let Some(newtype_body_field) = self.newtype_body_field() {
if let Some(newtype_body_field) = self.newtype_body_field() {
let mut field = newtype_body_field.clone(); let mut field = newtype_body_field.clone();
let ty = &field.ty; let ty = &field.ty;
let span = field.span(); let span = field.span();
request_body_struct = quote_spanned! {span=> quote_spanned! {span=>
/// Data in the request body. /// Data in the request body.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct RequestBody(#ty); struct RequestBody(#ty);
}; }
} else if self.has_body_fields() { } else if self.has_body_fields() {
let fields = self.fields.iter().fold(TokenStream::new(), |mut field_tokens, request_field| { let fields = self.fields.iter().filter_map(|request_field| {
match *request_field { match *request_field {
RequestField::Body(ref field) => { RequestField::Body(ref field) => {
let span = field.span(); let span = field.span();
Some(quote_spanned!(span=> #field))
field_tokens.append_all(quote_spanned!(span=> #field,));
field_tokens
} }
_ => field_tokens, _ => None,
} }
}); });
request_body_struct = quote! { quote! {
/// Data in the request body. /// Data in the request body.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct RequestBody { struct RequestBody {
#fields #(#fields),*
} }
}; }
} else { } else {
request_body_struct = TokenStream::new(); TokenStream::new()
} };
let request_path_struct; let request_path_struct = if self.has_path_fields() {
let fields = self.fields.iter().filter_map(|request_field| {
if self.has_path_fields() {
let fields = self.fields.iter().fold(TokenStream::new(), |mut field_tokens, request_field| {
match *request_field { match *request_field {
RequestField::Path(ref field) => { RequestField::Path(ref field) => {
let span = field.span(); let span = field.span();
field_tokens.append_all(quote_spanned!(span=> #field,)); Some(quote_spanned!(span=> #field))
field_tokens
} }
_ => field_tokens, _ => None,
} }
}); });
request_path_struct = quote! { quote! {
/// Data in the request path. /// Data in the request path.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct RequestPath { struct RequestPath {
#fields #(#fields),*
} }
}; }
} else { } else {
request_path_struct = TokenStream::new(); TokenStream::new()
} };
let request_query_struct; let request_query_struct = if self.has_query_fields() {
let fields = self.fields.iter().filter_map(|request_field| {
if self.has_query_fields() {
let fields = self.fields.iter().fold(TokenStream::new(), |mut field_tokens, request_field| {
match *request_field { match *request_field {
RequestField::Query(ref field) => { RequestField::Query(ref field) => {
let span = field.span(); let span = field.span();
Some(quote_spanned!(span=> #field))
field_tokens.append_all(quote_spanned!(span=> #field,));
field_tokens
} }
_ => field_tokens, _ => None,
} }
}); });
request_query_struct = quote! { quote! {
/// Data in the request's query string. /// Data in the request's query string.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct RequestQuery { struct RequestQuery {
#fields #(#fields),*
} }
}; }
} else { } else {
request_query_struct = TokenStream::new(); TokenStream::new()
} };
tokens.append_all(quote! { tokens.append_all(quote! {
#request_struct_header #request_struct_header

View File

@ -27,9 +27,7 @@ impl Response {
} }
pub fn init_fields(&self) -> TokenStream { pub fn init_fields(&self) -> TokenStream {
let mut tokens = TokenStream::new(); let fields = self.fields.iter().map(|response_field| {
for response_field in self.fields.iter() {
match *response_field { match *response_field {
ResponseField::Body(ref field) => { ResponseField::Body(ref field) => {
let field_name = field let field_name = field
@ -38,9 +36,9 @@ impl Response {
.expect("expected field to have an identifier"); .expect("expected field to have an identifier");
let span = field.span(); let span = field.span();
tokens.append_all(quote_spanned! {span=> quote_spanned! {span=>
#field_name: response_body.#field_name, #field_name: response_body.#field_name
}); }
} }
ResponseField::Header(ref field, ref header) => { ResponseField::Header(ref field, ref header) => {
let field_name = field let field_name = field
@ -50,13 +48,13 @@ impl Response {
let header_name = Ident::new(header.as_ref(), Span::call_site()); let header_name = Ident::new(header.as_ref(), Span::call_site());
let span = field.span(); let span = field.span();
tokens.append_all(quote_spanned! {span=> quote_spanned! {span=>
#field_name: headers.remove(::http::header::#header_name) #field_name: headers.remove(::http::header::#header_name)
.expect("response missing expected header") .expect("response missing expected header")
.to_str() .to_str()
.expect("failed to convert HeaderValue to str") .expect("failed to convert HeaderValue to str")
.to_owned(), .to_owned()
}); }
} }
ResponseField::NewtypeBody(ref field) => { ResponseField::NewtypeBody(ref field) => {
let field_name = field let field_name = field
@ -65,32 +63,36 @@ impl Response {
.expect("expected field to have an identifier"); .expect("expected field to have an identifier");
let span = field.span(); let span = field.span();
tokens.append_all(quote_spanned! {span=> quote_spanned! {span=>
#field_name: response_body, #field_name: response_body
}); }
} }
} }
} });
tokens quote! {
#(#fields,)*
}
} }
pub fn apply_header_fields(&self) -> TokenStream { pub fn apply_header_fields(&self) -> TokenStream {
let mut tokens = TokenStream::new(); let header_calls = self.fields.iter().filter_map(|response_field| {
for response_field in self.fields.iter() {
if let ResponseField::Header(ref field, ref header) = *response_field { if let ResponseField::Header(ref field, ref header) = *response_field {
let field_name = field.ident.as_ref().expect("expected field to have an identifier"); let field_name = field.ident.as_ref().expect("expected field to have an identifier");
let header_name = Ident::new(header.as_ref(), Span::call_site()); let header_name = Ident::new(header.as_ref(), Span::call_site());
let span = field.span(); let span = field.span();
tokens.append_all(quote_spanned! {span=> Some(quote_spanned! {span=>
.header(::http::header::#header_name, response.#field_name) .header(::http::header::#header_name, response.#field_name)
}); })
} else {
None
} }
} });
tokens quote! {
#(#header_calls)*
}
} }
pub fn to_body(&self) -> TokenStream { pub fn to_body(&self) -> TokenStream {
@ -112,7 +114,11 @@ impl Response {
} }
}); });
quote!(ResponseBody{#(#fields),*}) quote! {
ResponseBody {
#(#fields),*
}
}
} }
} }
@ -221,60 +227,53 @@ impl ToTokens for Response {
let response_struct_body = if self.fields.is_empty() { let response_struct_body = if self.fields.is_empty() {
quote!(;) quote!(;)
} else { } else {
let fields = self.fields.iter().fold(TokenStream::new(), |mut fields_tokens, response_field| { let fields = self.fields.iter().map(|response_field| {
let field = response_field.field(); let field = response_field.field();
let span = field.span(); let span = field.span();
let stripped_field = strip_serde_attrs(field); let stripped_field = strip_serde_attrs(field);
fields_tokens.append_all(quote_spanned!(span=> #stripped_field,)); quote_spanned!(span=> #stripped_field)
fields_tokens
}); });
quote! { quote! {
{ {
#fields #(#fields),*
} }
} }
}; };
let response_body_struct; let response_body_struct = if let Some(newtype_body_field) = self.newtype_body_field() {
if let Some(newtype_body_field) = self.newtype_body_field() {
let mut field = newtype_body_field.clone(); let mut field = newtype_body_field.clone();
let ty = &field.ty; let ty = &field.ty;
let span = field.span(); let span = field.span();
response_body_struct = quote_spanned! {span=> quote_spanned! {span=>
/// Data in the response body. /// Data in the response body.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct ResponseBody(#ty); struct ResponseBody(#ty);
}; }
} else if self.has_body_fields() { } else if self.has_body_fields() {
let fields = self.fields.iter().fold(TokenStream::new(), |mut field_tokens, response_field| { let fields = self.fields.iter().filter_map(|response_field| {
match *response_field { match *response_field {
ResponseField::Body(ref field) => { ResponseField::Body(ref field) => {
let span = field.span(); let span = field.span();
Some(quote_spanned!(span=> #field))
field_tokens.append_all(quote_spanned!(span=> #field,));
field_tokens
} }
_ => field_tokens, _ => None,
} }
}); });
response_body_struct = quote! { quote! {
/// Data in the response body. /// Data in the response body.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct ResponseBody { struct ResponseBody {
#fields #(#fields),*
} }
}; }
} else { } else {
response_body_struct = TokenStream::new(); TokenStream::new()
} };
tokens.append_all(quote! { tokens.append_all(quote! {
#response_struct_header #response_struct_header