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:
parent
6f0997808b
commit
3f64ac443f
3 changed files with 179 additions and 53 deletions
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
96
gotham_restful_derive/src/method.rs
Normal file
96
gotham_restful_derive/src/method.rs
Normal 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()
|
||||
}
|
Loading…
Add table
Reference in a new issue