1
0
Fork 0
mirror of https://gitlab.com/msrd0/gotham-restful.git synced 2025-06-06 22:00:45 +00:00

add derive macro for resource

This commit is contained in:
Dominic 2019-10-06 15:03:30 +02:00
parent 75c399d97a
commit 0cf7c9aa3a
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
9 changed files with 132 additions and 15 deletions

View file

@ -4,6 +4,8 @@ use proc_macro::TokenStream;
mod method;
use method::{expand_method, Method};
mod resource;
use resource::expand_resource;
#[cfg(feature = "openapi")]
mod openapi_type;
@ -14,6 +16,12 @@ pub fn derive_openapi_type(tokens : TokenStream) -> TokenStream
openapi_type::expand(tokens)
}
#[proc_macro_derive(Resource, attributes(rest_resource))]
pub fn derive_resource(tokens : TokenStream) -> TokenStream
{
expand_resource(tokens)
}
#[proc_macro_attribute]
pub fn rest_read_all(attr : TokenStream, item : TokenStream) -> TokenStream
{

View file

@ -7,6 +7,7 @@ use syn::{
ReturnType,
parse_macro_input
};
use std::str::FromStr;
pub enum Method
{
@ -19,9 +20,27 @@ pub enum Method
Delete
}
impl FromStr for Method
{
type Err = String;
fn from_str(str : &str) -> Result<Self, Self::Err>
{
match str {
"ReadAll" | "read_all" => Ok(Self::ReadAll),
"Read" | "read" => Ok(Self::Read),
"Create" | "create" => Ok(Self::Create),
"UpdateAll" | "update_all" => Ok(Self::UpdateAll),
"Update" | "update" => Ok(Self::Update),
"DeleteAll" | "delete_all" => Ok(Self::DeleteAll),
"Delete" | "delete" => Ok(Self::Delete),
_ => Err("unknown method".to_string())
}
}
}
impl Method
{
fn trait_ident(&self) -> Ident
pub fn trait_ident(&self) -> Ident
{
use Method::*;
@ -37,7 +56,7 @@ impl Method
format_ident!("Resource{}", name)
}
fn fn_ident(&self) -> Ident
pub fn fn_ident(&self) -> Ident
{
use Method::*;
@ -52,6 +71,11 @@ impl Method
};
format_ident!("{}", name)
}
pub fn setup_ident(&self) -> Ident
{
format_ident!("{}_setup_impl", self.fn_ident())
}
}
pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -> TokenStream
@ -87,6 +111,7 @@ pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -
let trait_ident = method.trait_ident();
let fn_ident = method.fn_ident();
let setup_ident = method.setup_ident();
let output = quote! {
impl ::gotham_restful::#trait_ident<#(#generics),*> for #ident
@ -98,6 +123,12 @@ pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -
#ret_stmt
}
}
#[deny(dead_code)]
fn #setup_ident<D : ::gotham_restful::DrawResourceRoutes>(route : &mut D)
{
route.#fn_ident::<#ident, #(#generics),*>();
}
};
output.into()
}

View file

@ -0,0 +1,60 @@
use crate::method::Method;
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{
parse::{Parse, ParseStream, Result as SynResult},
punctuated::Punctuated,
token::Comma,
Ident,
ItemStruct,
parenthesized,
parse_macro_input
};
use std::str::FromStr;
struct MethodList(Punctuated<Ident, Comma>);
impl Parse for MethodList
{
fn parse(input: ParseStream) -> SynResult<Self>
{
let content;
let _paren = parenthesized!(content in input);
let list : Punctuated<Ident, Comma> = Punctuated::parse_separated_nonempty(&content)?;
Ok(Self(list))
}
}
pub fn expand_resource(tokens : TokenStream) -> TokenStream
{
let input = parse_macro_input!(tokens as ItemStruct);
let ident = input.ident;
let methods : Vec<TokenStream2> = input.attrs.into_iter().filter(|attr|
attr.path.segments.iter().last().map(|segment| segment.ident.to_string()) == Some("rest_resource".to_string()) // TODO wtf
).flat_map(|attr| {
let m : MethodList = syn::parse2(attr.tokens).expect("unable to parse attributes");
m.0.into_iter()
}).map(|method| {
let method = Method::from_str(&method.to_string()).expect("unknown method");
let ident = method.setup_ident();
quote!(#ident(&mut route);)
}).collect();
let output = quote! {
impl ::gotham_restful::Resource for #ident
{
fn name() -> String
{
stringify!(#ident).to_string()
}
fn setup<D : ::gotham_restful::DrawResourceRoutes>(mut route : D)
{
#(#methods)*
}
}
};
output.into()
}