Implement ToTokens for Api, Request, and Response.

This commit is contained in:
Jimmy Cuadra 2017-05-13 18:16:43 -07:00
parent 029daf3e12
commit 06388333af
4 changed files with 79 additions and 65 deletions

View File

@ -2,8 +2,8 @@ use quote::{ToTokens, Tokens};
use metadata::Metadata; use metadata::Metadata;
use parse::Entry; use parse::Entry;
use request::{Request, RequestField}; use request::Request;
use response::{Response, ResponseField}; use response::Response;
#[derive(Debug)] #[derive(Debug)]
pub struct Api { pub struct Api {
@ -12,8 +12,8 @@ pub struct Api {
response: Response, response: Response,
} }
impl Api { impl ToTokens for Api {
pub fn output(&self) -> Tokens { fn to_tokens(&self, tokens: &mut Tokens) {
let description = &self.metadata.description; let description = &self.metadata.description;
let method = &self.metadata.method; let method = &self.metadata.method;
let name = &self.metadata.name; let name = &self.metadata.name;
@ -21,10 +21,18 @@ impl Api {
let rate_limited = &self.metadata.rate_limited; let rate_limited = &self.metadata.rate_limited;
let requires_authentication = &self.metadata.requires_authentication; let requires_authentication = &self.metadata.requires_authentication;
let request_types = self.generate_request_types(); let request_types = {
let response_types = self.generate_response_types(); let mut tokens = Tokens::new();
self.request.to_tokens(&mut tokens);
tokens
};
let response_types = {
let mut tokens = Tokens::new();
self.response.to_tokens(&mut tokens);
tokens
};
quote! { tokens.append(quote! {
use std::convert::TryFrom; use std::convert::TryFrom;
/// The API endpoint. /// The API endpoint.
@ -69,59 +77,7 @@ impl Api {
requires_authentication: #requires_authentication, requires_authentication: #requires_authentication,
}; };
} }
} });
}
fn generate_request_types(&self) -> Tokens {
let mut tokens = quote! {
/// Data for a request to this API endpoint.
#[derive(Debug)]
pub struct Request
};
if self.request.fields.len() == 0 {
tokens.append(";");
} else {
tokens.append("{");
for request_field in self.request.fields.iter() {
match *request_field {
RequestField::Body(ref field) => field.to_tokens(&mut tokens),
RequestField::Header(_, ref field) => field.to_tokens(&mut tokens),
RequestField::Path(_, ref field) => field.to_tokens(&mut tokens),
RequestField::Query(ref field) => field.to_tokens(&mut tokens),
}
}
tokens.append("}");
}
tokens
}
fn generate_response_types(&self) -> Tokens {
let mut tokens = quote! {
/// Data in the response from this API endpoint.
#[derive(Debug)]
pub struct Response
};
if self.response.fields.len() == 0 {
tokens.append(";");
} else {
tokens.append("{");
for response in self.response.fields.iter() {
match *response {
ResponseField::Body(ref field) => field.to_tokens(&mut tokens),
ResponseField::Header(_, ref field) => field.to_tokens(&mut tokens),
}
}
tokens.append("}");
}
tokens
} }
} }
@ -150,5 +106,3 @@ impl From<Vec<Entry>> for Api {
} }
} }
} }

View File

@ -12,6 +12,8 @@ extern crate syn;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::{ToTokens, Tokens};
use api::Api; use api::Api;
use parse::parse_entries; use parse::parse_entries;
@ -28,5 +30,9 @@ pub fn ruma_api(input: TokenStream) -> TokenStream {
let api = Api::from(entries); let api = Api::from(entries);
api.output().parse().expect("ruma_api! failed to parse output as a TokenStream") let mut tokens = Tokens::new();
api.to_tokens(&mut tokens);
tokens.parse().expect("ruma_api! failed to parse output tokens as a TokenStream")
} }

View File

@ -1,8 +1,9 @@
use quote::{ToTokens, Tokens};
use syn::{Field, Lit, MetaItem}; use syn::{Field, Lit, MetaItem};
#[derive(Debug)] #[derive(Debug)]
pub struct Request { pub struct Request {
pub fields: Vec<RequestField>, fields: Vec<RequestField>,
} }
impl From<Vec<Field>> for Request { impl From<Vec<Field>> for Request {
@ -43,6 +44,33 @@ impl From<Vec<Field>> for Request {
} }
} }
impl ToTokens for Request {
fn to_tokens(&self, mut tokens: &mut Tokens) {
tokens.append(quote! {
/// Data for a request to this API endpoint.
#[derive(Debug)]
pub struct Request
});
if self.fields.len() == 0 {
tokens.append(";");
} else {
tokens.append("{");
for request_field in self.fields.iter() {
match *request_field {
RequestField::Body(ref field) => field.to_tokens(&mut tokens),
RequestField::Header(_, ref field) => field.to_tokens(&mut tokens),
RequestField::Path(_, ref field) => field.to_tokens(&mut tokens),
RequestField::Query(ref field) => field.to_tokens(&mut tokens),
}
}
tokens.append("}");
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum RequestField { pub enum RequestField {
Body(Field), Body(Field),

View File

@ -1,8 +1,9 @@
use quote::{ToTokens, Tokens};
use syn::{Field, Lit, MetaItem}; use syn::{Field, Lit, MetaItem};
#[derive(Debug)] #[derive(Debug)]
pub struct Response { pub struct Response {
pub fields: Vec<ResponseField>, fields: Vec<ResponseField>,
} }
impl From<Vec<Field>> for Response { impl From<Vec<Field>> for Response {
@ -32,6 +33,31 @@ impl From<Vec<Field>> for Response {
} }
} }
impl ToTokens for Response {
fn to_tokens(&self, mut tokens: &mut Tokens) {
tokens.append(quote! {
/// Data in the response from this API endpoint.
#[derive(Debug)]
pub struct Response
});
if self.fields.len() == 0 {
tokens.append(";");
} else {
tokens.append("{");
for response in self.fields.iter() {
match *response {
ResponseField::Body(ref field) => field.to_tokens(&mut tokens),
ResponseField::Header(_, ref field) => field.to_tokens(&mut tokens),
}
}
tokens.append("}");
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum ResponseField { pub enum ResponseField {
Body(Field), Body(Field),