Fix remaining compiler errors.

This commit is contained in:
Jimmy Cuadra 2018-05-11 08:50:39 -07:00
parent 09e377d68e
commit 8f6bc5af77
4 changed files with 156 additions and 102 deletions

View File

@ -22,43 +22,82 @@ impl From<ExprStruct> for Metadata {
let mut requires_authentication = None; let mut requires_authentication = None;
for field in expr.fields { for field in expr.fields {
let Member::Named(identifier) = field.member; let identifier = match field.member {
Member::Named(identifier) => identifier,
_ => panic!("expected Member::Named"),
};
match identifier.as_ref() { match identifier.as_ref() {
"description" => { "description" => {
let Expr::Lit(expr_lit) = field.expr; let expr_lit = match field.expr {
let Lit::Str(lit_str) = expr_lit.lit; Expr::Lit(expr_lit) => expr_lit,
_ => panic!("expected Expr::Lit"),
};
let lit_str = match expr_lit.lit {
Lit::Str(lit_str) => lit_str,
_ => panic!("expected Lit::Str"),
};
description = Some(lit_str.value()); description = Some(lit_str.value());
} }
"method" => { "method" => {
let Expr::Path(expr_path) = field.expr; let expr_path = match field.expr {
Expr::Path(expr_path) => expr_path,
_ => panic!("expected Expr::Path"),
};
let path = expr_path.path; let path = expr_path.path;
let segments = path.segments; let segments = path.segments;
if segments.len() != 1 { if segments.len() != 1 {
panic!("ruma_api! expects a one component path for `metadata` `method`"); panic!("ruma_api! expects a one component path for `metadata` `method`");
} }
let pair = segments.first().unwrap(); // safe because we just checked let pair = segments.first().unwrap(); // safe because we just checked
let Pair::End(method_name) = pair; let method_name = match pair {
Pair::End(method_name) => method_name,
_ => panic!("expected Pair::End"),
};
method = Some(method_name.ident.to_string()); method = Some(method_name.ident.to_string());
} }
"name" => { "name" => {
let Expr::Lit(expr_lit) = field.expr; let expr_lit = match field.expr {
let Lit::Str(lit_str) = expr_lit.lit; Expr::Lit(expr_lit) => expr_lit,
_ => panic!("expected Expr::Lit"),
};
let lit_str = match expr_lit.lit {
Lit::Str(lit_str) => lit_str,
_ => panic!("expected Lit::Str"),
};
name = Some(lit_str.value()); name = Some(lit_str.value());
} }
"path" => { "path" => {
let Expr::Lit(expr_lit) = field.expr; let expr_lit = match field.expr {
let Lit::Str(lit_str) = expr_lit.lit; Expr::Lit(expr_lit) => expr_lit,
_ => panic!("expected Expr::Lit"),
};
let lit_str = match expr_lit.lit {
Lit::Str(lit_str) => lit_str,
_ => panic!("expected Lit::Str"),
};
path = Some(lit_str.value()); path = Some(lit_str.value());
} }
"rate_limited" => { "rate_limited" => {
let Expr::Lit(expr_lit) = field.expr; let expr_lit = match field.expr {
let Lit::Bool(lit_bool) = expr_lit.lit; Expr::Lit(expr_lit) => expr_lit,
_ => panic!("expected Expr::Lit"),
};
let lit_bool = match expr_lit.lit {
Lit::Bool(lit_bool) => lit_bool,
_ => panic!("expected Lit::Bool"),
};
rate_limited = Some(lit_bool.value) rate_limited = Some(lit_bool.value)
} }
"requires_authentication" => { "requires_authentication" => {
let Expr::Lit(expr_lit) = field.expr; let expr_lit = match field.expr {
let Lit::Bool(lit_bool) = expr_lit.lit; Expr::Lit(expr_lit) => expr_lit,
_ => panic!("expected Expr::Lit"),
};
let lit_bool = match expr_lit.lit {
Lit::Bool(lit_bool) => lit_bool,
_ => panic!("expected Lit::Bool"),
};
requires_authentication = Some(lit_bool.value) requires_authentication = Some(lit_bool.value)
} }
_ => panic!("ruma_api! metadata included unexpected field"), _ => panic!("ruma_api! metadata included unexpected field"),

View File

@ -1,7 +1,7 @@
use quote::{ToTokens, Tokens}; use quote::{ToTokens, Tokens};
use syn::punctuated::Pair; use syn::punctuated::Pair;
use syn::synom::Synom; use syn::synom::Synom;
use syn::{Expr, FieldValue, Ident, Meta}; use syn::{Expr, FieldValue, Ident, Member, Meta};
mod metadata; mod metadata;
mod request; mod request;
@ -18,7 +18,10 @@ pub fn strip_serde_attrs(field_value: &FieldValue) -> FieldValue {
let meta = attr.interpret_meta() let meta = attr.interpret_meta()
.expect("ruma_api! could not parse field attributes"); .expect("ruma_api! could not parse field attributes");
let Meta::List(meta_list) = meta; let meta_list = match meta {
Meta::List(meta_list) => meta_list,
_ => panic!("expected Meta::List"),
};
if meta_list.ident.as_ref() != "serde" { if meta_list.ident.as_ref() != "serde" {
return true; return true;
@ -52,13 +55,16 @@ impl From<Vec<Expr>> for Api {
_ => panic!("ruma_api! blocks should use struct syntax"), _ => panic!("ruma_api! blocks should use struct syntax"),
}; };
let segments = expr.path.segments; let segments = expr.path.segments.clone();
if segments.len() != 1 { if segments.len() != 1 {
panic!("ruma_api! blocks must be one of: metadata, request, or response"); panic!("ruma_api! blocks must be one of: metadata, request, or response");
} }
let Pair::End(last_segment) = segments.last().unwrap(); let last_segment = match segments.last().unwrap() {
Pair::End(last_segment) => last_segment,
_ => panic!("expected Pair::End"),
};
match last_segment.ident.as_ref() { match last_segment.ident.as_ref() {
"metadata" => metadata = Some(expr.into()), "metadata" => metadata = Some(expr.into()),
@ -138,23 +144,21 @@ impl ToTokens for Api {
}; };
for segment in path_str[1..].split('/') { for segment in path_str[1..].split('/') {
tokens.append(quote! { tokens.append_all(quote! {
path_segments.push path_segments.push
}); });
tokens.append("(");
if segment.starts_with(':') { if segment.starts_with(':') {
tokens.append("&request_path."); let what_is_this = &segment[1..];
tokens.append(&segment[1..]);
tokens.append(".to_string()");
} else {
tokens.append("\"");
tokens.append(segment);
tokens.append("\"");
}
tokens.append(");"); tokens.append_all(quote! {
(&request_path.#what_is_this.to_string());
});
} else {
tokens.append_all(quote! {
("#segment");
});
}
} }
tokens tokens
@ -179,7 +183,10 @@ impl ToTokens for Api {
}; };
let add_body_to_request = if let Some(field) = self.request.newtype_body_field() { let add_body_to_request = if let Some(field) = self.request.newtype_body_field() {
let field_name = field.ident.as_ref().expect("expected body field to have a name"); let field_name = match field.member {
Member::Named(field_name) => field_name,
_ => panic!("expected Member::Named"),
};
quote! { quote! {
let request_body = RequestBody(request.#field_name); let request_body = RequestBody(request.#field_name);
@ -201,10 +208,13 @@ impl ToTokens for Api {
}; };
let deserialize_response_body = if let Some(field) = self.response.newtype_body_field() { let deserialize_response_body = if let Some(field) = self.response.newtype_body_field() {
let field_type = &field.ty; let field_type = match field.expr {
Expr::Path(ref field_type) => field_type,
_ => panic!("expected Expr::Path"),
};
let mut tokens = Tokens::new(); let mut tokens = Tokens::new();
tokens.append(quote! { tokens.append_all(quote! {
let future_response = hyper_response.body() let future_response = hyper_response.body()
.fold::<_, _, Result<_, ::std::io::Error>>(Vec::new(), |mut bytes, chunk| { .fold::<_, _, Result<_, ::std::io::Error>>(Vec::new(), |mut bytes, chunk| {
bytes.write_all(&chunk)?; bytes.write_all(&chunk)?;
@ -218,13 +228,13 @@ impl ToTokens for Api {
}) })
}); });
tokens.append(".and_then(move |response_body| {"); tokens.append_all(".and_then(move |response_body| {".into_tokens());
tokens tokens
} else if self.response.has_body_fields() { } else if self.response.has_body_fields() {
let mut tokens = Tokens::new(); let mut tokens = Tokens::new();
tokens.append(quote! { tokens.append_all(quote! {
let future_response = hyper_response.body() let future_response = hyper_response.body()
.fold::<_, _, Result<_, ::std::io::Error>>(Vec::new(), |mut bytes, chunk| { .fold::<_, _, Result<_, ::std::io::Error>>(Vec::new(), |mut bytes, chunk| {
bytes.write_all(&chunk)?; bytes.write_all(&chunk)?;
@ -238,23 +248,23 @@ impl ToTokens for Api {
}) })
}); });
tokens.append(".and_then(move |response_body| {"); tokens.append_all(".and_then(move |response_body| {".into_tokens());
tokens tokens
} else { } else {
let mut tokens = Tokens::new(); let mut tokens = Tokens::new();
tokens.append(quote! { tokens.append_all(quote! {
let future_response = ::futures::future::ok(()) let future_response = ::futures::future::ok(())
}); });
tokens.append(".and_then(move |_| {"); tokens.append_all(".and_then(move |_| {".into_tokens());
tokens tokens
}; };
let mut closure_end = Tokens::new(); let mut closure_end = Tokens::new();
closure_end.append("});"); closure_end.append_all("});".into_tokens());
let extract_headers = if self.response.has_header_fields() { let extract_headers = if self.response.has_header_fields() {
quote! { quote! {
@ -270,7 +280,7 @@ impl ToTokens for Api {
Tokens::new() Tokens::new()
}; };
tokens.append(quote! { tokens.append_all(quote! {
#[allow(unused_imports)] #[allow(unused_imports)]
use std::io::Write as _Write; use std::io::Write as _Write;

View File

@ -1,6 +1,6 @@
use quote::{ToTokens, Tokens}; use quote::{ToTokens, Tokens};
use syn::synom::Synom; use syn::synom::Synom;
use syn::{ExprStruct, Field, FieldValue, FieldsNamed, Meta, NestedMeta}; use syn::{ExprStruct, Field, FieldValue, FieldsNamed, Member, Meta, NestedMeta};
use api::strip_serde_attrs; use api::strip_serde_attrs;
@ -54,9 +54,12 @@ impl Request {
let mut tokens = Tokens::new(); let mut tokens = Tokens::new();
for field in self.fields.iter().flat_map(|f| f.field_(request_field_kind)) { for field in self.fields.iter().flat_map(|f| f.field_(request_field_kind)) {
let field_name = field.ident.as_ref().expect("expected body field to have a name"); let field_name = match field.member {
Member::Named(field_name) => field_name,
_ => panic!("expected Member::Named"),
};
tokens.append(quote! { tokens.append_all(quote! {
#field_name: request.#field_name, #field_name: request.#field_name,
}); });
} }
@ -76,7 +79,10 @@ impl From<ExprStruct> for Request {
let meta = attr.interpret_meta() let meta = attr.interpret_meta()
.expect("ruma_api! could not parse request field attributes"); .expect("ruma_api! could not parse request field attributes");
let Meta::List(meta_list) = meta; let meta_list = match meta {
Meta::List(meta_list) => meta_list,
_ => panic!("expected Meta::List"),
};
if meta_list.ident.as_ref() != "ruma_api" { if meta_list.ident.as_ref() != "ruma_api" {
return true; return true;
@ -132,109 +138,102 @@ impl From<ExprStruct> for Request {
impl ToTokens for Request { impl ToTokens for Request {
fn to_tokens(&self, mut tokens: &mut Tokens) { fn to_tokens(&self, mut tokens: &mut Tokens) {
tokens.append(quote! { tokens.append_all(quote! {
/// Data for a request to this API endpoint. /// Data for a request to this API endpoint.
#[derive(Debug)] #[derive(Debug)]
pub struct Request pub struct Request
}); });
if self.fields.len() == 0 { if self.fields.len() == 0 {
tokens.append(";"); tokens.append_all(";".into_tokens());
} else { } else {
tokens.append("{"); tokens.append_all("{".into_tokens());
for request_field in self.fields.iter() { for request_field in self.fields.iter() {
strip_serde_attrs(request_field.field()).to_tokens(&mut tokens); strip_serde_attrs(request_field.field()).to_tokens(&mut tokens);
tokens.append(","); tokens.append_all(",".into_tokens());
} }
tokens.append("}"); tokens.append_all("}".into_tokens());
} }
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 expr = field.expr;
field.ident = None; tokens.append_all(quote! {
tokens.append(quote! {
/// Data in the request body. /// Data in the request body.
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
struct RequestBody struct RequestBody(#expr);
}); });
tokens.append("(");
field.to_tokens(&mut tokens);
tokens.append(");");
} else if self.has_body_fields() { } else if self.has_body_fields() {
tokens.append(quote! { tokens.append_all(quote! {
/// Data in the request body. /// Data in the request body.
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
struct RequestBody struct RequestBody
}); });
tokens.append("{"); tokens.append_all("{".into_tokens());
for request_field in self.fields.iter() { for request_field in self.fields.iter() {
match *request_field { match *request_field {
RequestField::Body(ref field) => { RequestField::Body(ref field) => {
field.to_tokens(&mut tokens); field.to_tokens(&mut tokens);
tokens.append(","); tokens.append_all(",".into_tokens());
} }
_ => {} _ => {}
} }
} }
tokens.append("}"); tokens.append_all("}".into_tokens());
} }
if self.has_path_fields() { if self.has_path_fields() {
tokens.append(quote! { tokens.append_all(quote! {
/// Data in the request path. /// Data in the request path.
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
struct RequestPath struct RequestPath
}); });
tokens.append("{"); tokens.append_all("{".into_tokens());
for request_field in self.fields.iter() { for request_field in self.fields.iter() {
match *request_field { match *request_field {
RequestField::Path(ref field) => { RequestField::Path(ref field) => {
field.to_tokens(&mut tokens); field.to_tokens(&mut tokens);
tokens.append(","); tokens.append_all(",".into_tokens());
} }
_ => {} _ => {}
} }
} }
tokens.append("}"); tokens.append_all("}".into_tokens());
} }
if self.has_query_fields() { if self.has_query_fields() {
tokens.append(quote! { tokens.append_all(quote! {
/// Data in the request's query string. /// Data in the request's query string.
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
struct RequestQuery struct RequestQuery
}); });
tokens.append("{"); tokens.append_all("{".into_tokens());
for request_field in self.fields.iter() { for request_field in self.fields.iter() {
match *request_field { match *request_field {
RequestField::Query(ref field) => { RequestField::Query(ref field) => {
field.to_tokens(&mut tokens); field.to_tokens(&mut tokens);
tokens.append(","); tokens.append_all(",".into_tokens());
} }
_ => {} _ => {}
} }
} }
tokens.append("}"); tokens.append_all("}".into_tokens());
} }
} }
} }

View File

@ -1,5 +1,5 @@
use quote::{ToTokens, Tokens}; use quote::{ToTokens, Tokens};
use syn::{ExprStruct, Field, FieldValue, FieldsNamed, Meta, NestedMeta}; use syn::{Expr, ExprStruct, Field, FieldValue, FieldsNamed, Member, Meta, NestedMeta};
use api::strip_serde_attrs; use api::strip_serde_attrs;
@ -26,28 +26,38 @@ impl Response {
for response_field in self.fields.iter() { 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.ident.as_ref() let field_name = match field.member {
.expect("expected body field to have a name"); Member::Named(field_name) => field_name,
_ => panic!("expected Member::Named"),
};
tokens.append(quote! { tokens.append_all(quote! {
#field_name: response_body.#field_name, #field_name: response_body.#field_name,
}); });
} }
ResponseField::Header(ref field) => { ResponseField::Header(ref field) => {
let field_name = field.ident.as_ref() let field_name = match field.member {
.expect("expected body field to have a name"); Member::Named(field_name) => field_name,
let field_type = &field.ty; _ => panic!("expected Member::Named"),
};
tokens.append(quote! { let field_type = match field.expr {
Expr::Path(ref field_type) => field_type,
_ => panic!("expected Expr::Path"),
};
tokens.append_all(quote! {
#field_name: headers.remove::<#field_type>() #field_name: headers.remove::<#field_type>()
.expect("missing expected request header"), .expect("missing expected request header"),
}); });
} }
ResponseField::NewtypeBody(ref field) => { ResponseField::NewtypeBody(ref field) => {
let field_name = field.ident.as_ref() let field_name = match field.member {
.expect("expected body field to have a name"); Member::Named(field_name) => field_name,
_ => panic!("expected Member::Named"),
};
tokens.append(quote! { tokens.append_all(quote! {
#field_name: response_body, #field_name: response_body,
}); });
} }
@ -57,7 +67,7 @@ impl Response {
tokens tokens
} }
pub fn newtype_body_field(&self) -> Option<&Field> { pub fn newtype_body_field(&self) -> Option<&FieldValue> {
for response_field in self.fields.iter() { for response_field in self.fields.iter() {
match *response_field { match *response_field {
ResponseField::NewtypeBody(ref field) => { ResponseField::NewtypeBody(ref field) => {
@ -84,7 +94,10 @@ impl From<ExprStruct> for Response {
let meta = attr.interpret_meta() let meta = attr.interpret_meta()
.expect("ruma_api! could not parse response field attributes"); .expect("ruma_api! could not parse response field attributes");
let Meta::List(meta_list) = meta; let meta_list = match meta {
Meta::List(meta_list) => meta_list,
_ => panic!("expected Meta::List"),
};
if meta_list.ident.as_ref() != "ruma_api" { if meta_list.ident.as_ref() != "ruma_api" {
return true; return true;
@ -141,63 +154,56 @@ impl From<ExprStruct> for Response {
impl ToTokens for Response { impl ToTokens for Response {
fn to_tokens(&self, mut tokens: &mut Tokens) { fn to_tokens(&self, mut tokens: &mut Tokens) {
tokens.append(quote! { tokens.append_all(quote! {
/// Data in the response from this API endpoint. /// Data in the response from this API endpoint.
#[derive(Debug)] #[derive(Debug)]
pub struct Response pub struct Response
}); });
if self.fields.len() == 0 { if self.fields.len() == 0 {
tokens.append(";"); tokens.append_all(";".into_tokens());
} else { } else {
tokens.append("{"); tokens.append_all("{".into_tokens());
for response_field in self.fields.iter() { for response_field in self.fields.iter() {
strip_serde_attrs(response_field.field()).to_tokens(&mut tokens); strip_serde_attrs(response_field.field()).to_tokens(&mut tokens);
tokens.append(","); tokens.append_all(",".into_tokens());
} }
tokens.append("}"); tokens.append_all("}".into_tokens());
} }
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 expr = field.expr;
field.ident = None; tokens.append_all(quote! {
tokens.append(quote! {
/// Data in the response body. /// Data in the response body.
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct ResponseBody struct ResponseBody(#expr);
}); });
tokens.append("(");
field.to_tokens(&mut tokens);
tokens.append(");");
} else if self.has_body_fields() { } else if self.has_body_fields() {
tokens.append(quote! { tokens.append_all(quote! {
/// Data in the response body. /// Data in the response body.
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct ResponseBody struct ResponseBody
}); });
tokens.append("{"); tokens.append_all("{".into_tokens());
for response_field in self.fields.iter() { for response_field in self.fields.iter() {
match *response_field { match *response_field {
ResponseField::Body(ref field) => { ResponseField::Body(ref field) => {
field.to_tokens(&mut tokens); field.to_tokens(&mut tokens);
tokens.append(","); tokens.append_all(",".into_tokens());
} }
_ => {} _ => {}
} }
} }
tokens.append("}"); tokens.append_all("}".into_tokens());
} }
} }
} }