1
0
Fork 0
mirror of https://gitlab.com/msrd0/gotham-restful.git synced 2025-02-23 04:52:28 +00:00

add proc macro attributes for all rest methods

This commit is contained in:
Dominic 2019-10-05 00:21:41 +02:00
parent 6f0997808b
commit 3f64ac443f
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
3 changed files with 179 additions and 53 deletions

View file

@ -25,83 +25,62 @@ rest_resource!{Users, route => {
route.update::<Self, _, _, _>();
}}
#[derive(Deserialize, OpenapiType, Serialize)]
struct TestStruct
{
foo : String
}
#[derive(Deserialize, OpenapiType, Serialize)]
struct User
{
username : String,
test : Option<Vec<TestStruct>>
username : String
}
impl ResourceReadAll<Success<Vec<Option<User>>>> for Users
#[rest_read_all(Users)]
fn read_all(_state : &mut State) -> Success<Vec<Option<User>>>
{
fn read_all(_state : &mut State) -> Success<Vec<Option<User>>>
{
vec![Username().fake(), Username().fake()]
.into_iter()
.map(|username| Some(User { username, test: None }))
.collect::<Vec<Option<User>>>()
.into()
}
vec![Username().fake(), Username().fake()]
.into_iter()
.map(|username| Some(User { username }))
.collect::<Vec<Option<User>>>()
.into()
}
impl ResourceRead<u64, Success<User>> for Users
#[rest_read(Users)]
fn read(_state : &mut State, id : u64) -> Success<User>
{
fn read(_state : &mut State, id : u64) -> Success<User>
{
let username : String = Username().fake();
User { username: format!("{}{}", username, id), test: None }.into()
}
let username : String = Username().fake();
User { username: format!("{}{}", username, id) }.into()
}
impl ResourceCreate<User, Success<()>> for Users
#[rest_create(Users)]
fn create(_state : &mut State, body : User) -> Success<()>
{
fn create(_state : &mut State, body : User) -> Success<()>
{
info!("Created User: {}", body.username);
().into()
}
info!("Created User: {}", body.username);
().into()
}
impl ResourceUpdateAll<Vec<User>, Success<()>> for Users
#[rest_update_all(Users)]
fn update_all(_state : &mut State, body : Vec<User>) -> Success<()>
{
fn update_all(_state : &mut State, body : Vec<User>) -> Success<()>
{
info!("Changing all Users to {:?}", body.into_iter().map(|u| u.username).collect::<Vec<String>>());
().into()
}
info!("Changing all Users to {:?}", body.into_iter().map(|u| u.username).collect::<Vec<String>>());
().into()
}
impl ResourceUpdate<u64, User, Success<()>> for Users
#[rest_update(Users)]
fn update(_state : &mut State, id : u64, body : User) -> Success<()>
{
fn update(_state : &mut State, id : u64, body : User) -> Success<()>
{
info!("Change User {} to {}", id, body.username);
().into()
}
info!("Change User {} to {}", id, body.username);
().into()
}
impl ResourceDeleteAll<Success<()>> for Users
#[rest_delete_all(Users)]
fn delete_all(_state : &mut State) -> Success<()>
{
fn delete_all(_state : &mut State) -> Success<()>
{
info!("Delete all Users");
().into()
}
info!("Delete all Users");
().into()
}
impl ResourceDelete<u64, Success<()>> for Users
#[rest_delete(Users)]
fn delete(_state : &mut State, id : u64) -> Success<()>
{
fn delete(_state : &mut State, id : u64) -> Success<()>
{
info!("Delete User {}", id);
().into()
}
info!("Delete User {}", id);
().into()
}
const ADDR : &str = "127.0.0.1:18080";

View file

@ -2,6 +2,8 @@ extern crate proc_macro;
use proc_macro::TokenStream;
mod method;
use method::{expand_method, Method};
#[cfg(feature = "openapi")]
mod openapi_type;
@ -11,3 +13,52 @@ pub fn derive_openapi_type(tokens : TokenStream) -> TokenStream
{
openapi_type::expand(tokens)
}
#[proc_macro_attribute]
pub fn rest_read_all(attr : TokenStream, item : TokenStream) -> TokenStream
{
let output = expand_method(Method::ReadAll, attr, item);
output
}
#[proc_macro_attribute]
pub fn rest_read(attr : TokenStream, item : TokenStream) -> TokenStream
{
let output = expand_method(Method::Read, attr, item);
output
}
#[proc_macro_attribute]
pub fn rest_create(attr : TokenStream, item : TokenStream) -> TokenStream
{
let output = expand_method(Method::Create, attr, item);
output
}
#[proc_macro_attribute]
pub fn rest_update_all(attr : TokenStream, item : TokenStream) -> TokenStream
{
let output = expand_method(Method::UpdateAll, attr, item);
output
}
#[proc_macro_attribute]
pub fn rest_update(attr : TokenStream, item : TokenStream) -> TokenStream
{
let output = expand_method(Method::Update, attr, item);
output
}
#[proc_macro_attribute]
pub fn rest_delete_all(attr : TokenStream, item : TokenStream) -> TokenStream
{
let output = expand_method(Method::DeleteAll, attr, item);
output
}
#[proc_macro_attribute]
pub fn rest_delete(attr : TokenStream, item : TokenStream) -> TokenStream
{
let output = expand_method(Method::Delete, attr, item);
output
}

View file

@ -0,0 +1,96 @@
use proc_macro::TokenStream;
use proc_macro2::{Ident, TokenStream as TokenStream2};
use quote::{format_ident, quote};
use syn::{
FnArg,
ItemFn,
ReturnType,
parse_macro_input
};
pub enum Method
{
ReadAll,
Read,
Create,
UpdateAll,
Update,
DeleteAll,
Delete
}
impl Method
{
fn trait_ident(&self) -> Ident
{
use Method::*;
let name = match self {
ReadAll => "ReadAll",
Read => "Read",
Create => "Create",
UpdateAll => "UpdateAll",
Update => "Update",
DeleteAll => "DeleteAll",
Delete => "Delete"
};
format_ident!("Resource{}", name)
}
fn fn_ident(&self) -> Ident
{
use Method::*;
let name = match self {
ReadAll => "read_all",
Read => "read",
Create => "create",
UpdateAll => "update_all",
Update => "update",
DeleteAll => "delete_all",
Delete => "delete"
};
format_ident!("{}", name)
}
}
pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -> TokenStream
{
let ident = parse_macro_input!(attrs as Ident);
let fun = parse_macro_input!(item as ItemFn);
let ret = match fun.sig.output {
ReturnType::Default => quote!(()),
ReturnType::Type(_, ty) => quote!(#ty)
};
let args : Vec<(TokenStream2, TokenStream2)> = fun.sig.inputs.iter().map(|arg| match arg {
FnArg::Typed(arg) => {
let pat = &arg.pat;
let ty = &arg.ty;
(quote!(#pat), quote!(#ty))
},
FnArg::Receiver(_) => panic!("didn't expect self parameter")
}).collect();
let mut generics : Vec<TokenStream2> = Vec::new();
for i in 1..args.len()
{
let (_, ty) = &args[i];
generics.push(quote!(#ty));
}
generics.push(quote!(#ret));
let args : Vec<TokenStream2> = args.into_iter().map(|(pat, ty)| quote!(#pat : #ty)).collect();
let block = fun.block;
let trait_ident = method.trait_ident();
let fn_ident = method.fn_ident();
let output = quote! {
impl ::gotham_restful::#trait_ident<#(#generics),*> for #ident
where #ident : ::gotham_restful::Resource
{
fn #fn_ident(#(#args),*) -> #ret
#block
}
};
output.into()
}