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, _, _, _>();
|
route.update::<Self, _, _, _>();
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#[derive(Deserialize, OpenapiType, Serialize)]
|
|
||||||
struct TestStruct
|
|
||||||
{
|
|
||||||
foo : String
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, OpenapiType, Serialize)]
|
#[derive(Deserialize, OpenapiType, Serialize)]
|
||||||
struct User
|
struct User
|
||||||
{
|
{
|
||||||
username : String,
|
username : String
|
||||||
test : Option<Vec<TestStruct>>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
vec![Username().fake(), Username().fake()]
|
.map(|username| Some(User { username }))
|
||||||
.into_iter()
|
.collect::<Vec<Option<User>>>()
|
||||||
.map(|username| Some(User { username, test: None }))
|
.into()
|
||||||
.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) }.into()
|
||||||
let username : String = Username().fake();
|
|
||||||
User { username: format!("{}{}", username, id), test: None }.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";
|
const ADDR : &str = "127.0.0.1:18080";
|
||||||
|
|
|
@ -2,6 +2,8 @@ extern crate proc_macro;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
mod method;
|
||||||
|
use method::{expand_method, Method};
|
||||||
#[cfg(feature = "openapi")]
|
#[cfg(feature = "openapi")]
|
||||||
mod openapi_type;
|
mod openapi_type;
|
||||||
|
|
||||||
|
@ -11,3 +13,52 @@ pub fn derive_openapi_type(tokens : TokenStream) -> TokenStream
|
||||||
{
|
{
|
||||||
openapi_type::expand(tokens)
|
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