2020-04-06 16:20:08 +00:00
|
|
|
use heck::{CamelCase, SnakeCase};
|
2019-10-05 00:21:41 +02:00
|
|
|
use proc_macro::TokenStream;
|
2020-04-11 19:20:30 +02:00
|
|
|
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
|
2019-10-05 00:21:41 +02:00
|
|
|
use quote::{format_ident, quote};
|
|
|
|
use syn::{
|
2020-04-08 22:07:33 +02:00
|
|
|
spanned::Spanned,
|
2020-01-22 16:53:02 +00:00
|
|
|
Attribute,
|
2020-04-07 20:44:02 +00:00
|
|
|
AttributeArgs,
|
2020-04-08 22:07:33 +02:00
|
|
|
Error,
|
2019-10-05 00:21:41 +02:00
|
|
|
FnArg,
|
|
|
|
ItemFn,
|
2020-04-07 20:44:02 +00:00
|
|
|
Lit,
|
2020-04-11 18:13:36 +00:00
|
|
|
LitBool,
|
2020-04-07 20:44:02 +00:00
|
|
|
Meta,
|
|
|
|
NestedMeta,
|
2020-01-22 16:53:02 +00:00
|
|
|
PatType,
|
2019-10-05 00:21:41 +02:00
|
|
|
ReturnType,
|
2020-01-14 23:16:31 +01:00
|
|
|
Type,
|
2019-10-05 00:21:41 +02:00
|
|
|
parse_macro_input
|
|
|
|
};
|
2019-10-06 15:03:30 +02:00
|
|
|
use std::str::FromStr;
|
2019-10-05 00:21:41 +02:00
|
|
|
|
|
|
|
pub enum Method
|
|
|
|
{
|
|
|
|
ReadAll,
|
|
|
|
Read,
|
2019-10-13 17:43:42 +02:00
|
|
|
Search,
|
2019-10-05 00:21:41 +02:00
|
|
|
Create,
|
|
|
|
UpdateAll,
|
|
|
|
Update,
|
|
|
|
DeleteAll,
|
|
|
|
Delete
|
|
|
|
}
|
|
|
|
|
2019-10-06 15:03:30 +02:00
|
|
|
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),
|
2019-10-13 17:43:42 +02:00
|
|
|
"Search" | "search" => Ok(Self::Search),
|
2019-10-06 15:03:30 +02:00
|
|
|
"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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-05 00:21:41 +02:00
|
|
|
impl Method
|
|
|
|
{
|
2020-04-06 16:20:08 +00:00
|
|
|
pub fn type_names(&self) -> Vec<&'static str>
|
|
|
|
{
|
|
|
|
use Method::*;
|
|
|
|
|
|
|
|
match self {
|
|
|
|
ReadAll => vec![],
|
|
|
|
Read => vec!["ID"],
|
|
|
|
Search => vec!["Query"],
|
|
|
|
Create => vec!["Body"],
|
|
|
|
UpdateAll => vec!["Body"],
|
|
|
|
Update => vec!["ID", "Body"],
|
|
|
|
DeleteAll => vec![],
|
|
|
|
Delete => vec!["ID"]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-06 15:03:30 +02:00
|
|
|
pub fn trait_ident(&self) -> Ident
|
2019-10-05 00:21:41 +02:00
|
|
|
{
|
|
|
|
use Method::*;
|
|
|
|
|
|
|
|
let name = match self {
|
|
|
|
ReadAll => "ReadAll",
|
|
|
|
Read => "Read",
|
2019-10-13 17:43:42 +02:00
|
|
|
Search => "Search",
|
2019-10-05 00:21:41 +02:00
|
|
|
Create => "Create",
|
|
|
|
UpdateAll => "UpdateAll",
|
|
|
|
Update => "Update",
|
|
|
|
DeleteAll => "DeleteAll",
|
|
|
|
Delete => "Delete"
|
|
|
|
};
|
|
|
|
format_ident!("Resource{}", name)
|
|
|
|
}
|
|
|
|
|
2019-10-06 15:03:30 +02:00
|
|
|
pub fn fn_ident(&self) -> Ident
|
2019-10-05 00:21:41 +02:00
|
|
|
{
|
|
|
|
use Method::*;
|
|
|
|
|
|
|
|
let name = match self {
|
|
|
|
ReadAll => "read_all",
|
|
|
|
Read => "read",
|
2019-10-13 17:43:42 +02:00
|
|
|
Search => "search",
|
2019-10-05 00:21:41 +02:00
|
|
|
Create => "create",
|
|
|
|
UpdateAll => "update_all",
|
|
|
|
Update => "update",
|
|
|
|
DeleteAll => "delete_all",
|
|
|
|
Delete => "delete"
|
|
|
|
};
|
|
|
|
format_ident!("{}", name)
|
|
|
|
}
|
2019-10-06 15:03:30 +02:00
|
|
|
|
2020-04-07 20:44:02 +00:00
|
|
|
pub fn mod_ident(&self, resource : &str) -> Ident
|
2020-04-06 16:20:08 +00:00
|
|
|
{
|
|
|
|
format_ident!("_gotham_restful_resource_{}_method_{}", resource.to_snake_case(), self.fn_ident())
|
|
|
|
}
|
|
|
|
|
2020-04-07 20:44:02 +00:00
|
|
|
pub fn handler_struct_ident(&self, resource : &str) -> Ident
|
2020-04-06 16:20:08 +00:00
|
|
|
{
|
|
|
|
format_ident!("{}{}Handler", resource.to_camel_case(), self.trait_ident())
|
|
|
|
}
|
|
|
|
|
2020-04-07 20:44:02 +00:00
|
|
|
pub fn setup_ident(&self, resource : &str) -> Ident
|
2019-10-06 15:03:30 +02:00
|
|
|
{
|
2019-10-27 20:44:23 +00:00
|
|
|
format_ident!("{}_{}_setup_impl", resource.to_snake_case(), self.fn_ident())
|
2019-10-06 15:03:30 +02:00
|
|
|
}
|
2019-10-05 00:21:41 +02:00
|
|
|
}
|
|
|
|
|
2020-01-22 16:53:02 +00:00
|
|
|
enum MethodArgumentType
|
|
|
|
{
|
|
|
|
StateRef,
|
|
|
|
StateMutRef,
|
|
|
|
MethodArg(Type),
|
|
|
|
DatabaseConnection(Type),
|
|
|
|
AuthStatus(Type),
|
|
|
|
AuthStatusRef(Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MethodArgumentType
|
|
|
|
{
|
|
|
|
fn is_method_arg(&self) -> bool
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
Self::MethodArg(_) => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_database_conn(&self) -> bool
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
Self::DatabaseConnection(_) => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_auth_status(&self) -> bool
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
Self::AuthStatus(_) | Self::AuthStatusRef(_) => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn quote_ty(&self) -> Option<TokenStream2>
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
Self::MethodArg(ty) => Some(quote!(#ty)),
|
|
|
|
Self::DatabaseConnection(ty) => Some(quote!(#ty)),
|
|
|
|
Self::AuthStatus(ty) => Some(quote!(#ty)),
|
|
|
|
Self::AuthStatusRef(ty) => Some(quote!(#ty)),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct MethodArgument
|
|
|
|
{
|
|
|
|
ident : Ident,
|
2020-04-11 19:20:30 +02:00
|
|
|
ident_span : Span,
|
2020-01-22 16:53:02 +00:00
|
|
|
ty : MethodArgumentType
|
|
|
|
}
|
|
|
|
|
2020-04-11 19:20:30 +02:00
|
|
|
impl Spanned for MethodArgument
|
|
|
|
{
|
|
|
|
fn span(&self) -> Span
|
|
|
|
{
|
|
|
|
self.ident_span
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-08 22:07:33 +02:00
|
|
|
fn interpret_arg_ty(index : usize, attrs : &[Attribute], name : &str, ty : Type) -> Result<MethodArgumentType, Error>
|
2020-01-22 16:53:02 +00:00
|
|
|
{
|
|
|
|
let attr = attrs.into_iter()
|
|
|
|
.filter(|arg| arg.path.segments.iter().filter(|path| &path.ident.to_string() == "rest_arg").nth(0).is_some())
|
|
|
|
.nth(0)
|
|
|
|
.map(|arg| arg.tokens.to_string());
|
|
|
|
|
|
|
|
if cfg!(feature = "auth") && (attr.as_deref() == Some("auth") || (attr.is_none() && name == "auth"))
|
|
|
|
{
|
2020-04-08 22:07:33 +02:00
|
|
|
return Ok(match ty {
|
2020-01-22 16:53:02 +00:00
|
|
|
Type::Reference(ty) => MethodArgumentType::AuthStatusRef(*ty.elem),
|
|
|
|
ty => MethodArgumentType::AuthStatus(ty)
|
2020-04-08 22:07:33 +02:00
|
|
|
});
|
2020-01-22 16:53:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if cfg!(feature = "database") && (attr.as_deref() == Some("connection") || attr.as_deref() == Some("conn") || (attr.is_none() && name == "conn"))
|
|
|
|
{
|
2020-04-08 22:07:33 +02:00
|
|
|
return Ok(MethodArgumentType::DatabaseConnection(match ty {
|
2020-01-22 16:53:02 +00:00
|
|
|
Type::Reference(ty) => *ty.elem,
|
|
|
|
ty => ty
|
2020-04-08 22:07:33 +02:00
|
|
|
}));
|
2020-01-22 16:53:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if index == 0
|
|
|
|
{
|
|
|
|
return match ty {
|
2020-04-08 22:07:33 +02:00
|
|
|
Type::Reference(ty) => Ok(if ty.mutability.is_none() { MethodArgumentType::StateRef } else { MethodArgumentType::StateMutRef }),
|
|
|
|
_ => Err(Error::new(ty.span(), "The first argument, unless some feature is used, has to be a (mutable) reference to gotham::state::State"))
|
2020-01-22 16:53:02 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-04-08 22:07:33 +02:00
|
|
|
Ok(MethodArgumentType::MethodArg(ty))
|
2020-01-22 16:53:02 +00:00
|
|
|
}
|
|
|
|
|
2020-04-08 22:07:33 +02:00
|
|
|
fn interpret_arg(index : usize, arg : &PatType) -> Result<MethodArgument, Error>
|
2020-01-22 16:53:02 +00:00
|
|
|
{
|
|
|
|
let pat = &arg.pat;
|
|
|
|
let ident = format_ident!("arg{}", index);
|
|
|
|
let orig_name = quote!(#pat);
|
2020-04-08 22:07:33 +02:00
|
|
|
let ty = interpret_arg_ty(index, &arg.attrs, &orig_name.to_string(), *arg.ty.clone())?;
|
2020-01-22 16:53:02 +00:00
|
|
|
|
2020-04-11 19:20:30 +02:00
|
|
|
Ok(MethodArgument { ident, ident_span: arg.pat.span(), ty })
|
2020-01-22 16:53:02 +00:00
|
|
|
}
|
|
|
|
|
2020-04-07 20:44:02 +00:00
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn expand_operation_id(attrs : &AttributeArgs) -> TokenStream2
|
|
|
|
{
|
|
|
|
let mut operation_id : Option<&Lit> = None;
|
|
|
|
for meta in attrs
|
|
|
|
{
|
|
|
|
match meta {
|
|
|
|
NestedMeta::Meta(Meta::NameValue(kv)) => {
|
|
|
|
if kv.path.segments.last().map(|p| p.ident.to_string()) == Some("operation_id".to_owned())
|
|
|
|
{
|
|
|
|
operation_id = Some(&kv.lit)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match operation_id {
|
|
|
|
Some(operation_id) => quote! {
|
|
|
|
fn operation_id() -> Option<String>
|
|
|
|
{
|
|
|
|
Some(#operation_id.to_string())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
None => quote!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(feature = "openapi"))]
|
|
|
|
fn expand_operation_id(_ : &AttributeArgs) -> TokenStream2
|
|
|
|
{
|
|
|
|
quote!()
|
|
|
|
}
|
|
|
|
|
2020-04-11 18:13:36 +00:00
|
|
|
fn expand_wants_auth(attrs : &AttributeArgs, default : bool) -> TokenStream2
|
|
|
|
{
|
|
|
|
let default_lit = Lit::Bool(LitBool { value: default, span: Span::call_site() });
|
|
|
|
let mut wants_auth = &default_lit;
|
|
|
|
for meta in attrs
|
|
|
|
{
|
|
|
|
match meta {
|
|
|
|
NestedMeta::Meta(Meta::NameValue(kv)) => {
|
|
|
|
if kv.path.segments.last().map(|p| p.ident.to_string()) == Some("wants_auth".to_owned())
|
|
|
|
{
|
|
|
|
wants_auth = &kv.lit
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
quote! {
|
|
|
|
fn wants_auth() -> bool
|
|
|
|
{
|
|
|
|
#wants_auth
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-08 22:07:33 +02:00
|
|
|
fn expand(method : Method, attrs : TokenStream, item : TokenStream) -> Result<TokenStream2, Error>
|
2019-10-05 00:21:41 +02:00
|
|
|
{
|
2019-10-14 02:17:25 +02:00
|
|
|
let krate = super::krate();
|
2020-04-07 20:44:02 +00:00
|
|
|
|
|
|
|
// parse attributes
|
2020-04-08 22:07:33 +02:00
|
|
|
let mut method_attrs = parse_macro_input::parse::<AttributeArgs>(attrs)?;
|
2020-04-07 20:44:02 +00:00
|
|
|
let resource_path = match method_attrs.remove(0) {
|
|
|
|
NestedMeta::Meta(Meta::Path(path)) => path,
|
2020-04-08 22:07:33 +02:00
|
|
|
p => return Err(Error::new(p.span(), "Expected name of the Resource struct this method belongs to"))
|
2020-04-07 20:44:02 +00:00
|
|
|
};
|
2020-04-08 22:07:33 +02:00
|
|
|
let resource_name = resource_path.segments.last().map(|s| s.ident.to_string())
|
|
|
|
.ok_or_else(|| Error::new(resource_path.span(), "Resource name must not be empty"))?;
|
2020-04-07 20:44:02 +00:00
|
|
|
|
2020-04-08 22:07:33 +02:00
|
|
|
let fun = parse_macro_input::parse::<ItemFn>(item)?;
|
2019-10-27 20:44:23 +00:00
|
|
|
let fun_ident = &fun.sig.ident;
|
|
|
|
let fun_vis = &fun.vis;
|
2019-10-05 00:21:41 +02:00
|
|
|
|
2019-10-27 20:44:23 +00:00
|
|
|
let trait_ident = method.trait_ident();
|
|
|
|
let method_ident = method.fn_ident();
|
2020-04-07 20:44:02 +00:00
|
|
|
let mod_ident = method.mod_ident(&resource_name);
|
|
|
|
let handler_ident = method.handler_struct_ident(&resource_name);
|
|
|
|
let setup_ident = method.setup_ident(&resource_name);
|
2019-10-27 20:44:23 +00:00
|
|
|
|
|
|
|
let (ret, is_no_content) = match &fun.sig.output {
|
2019-10-14 02:17:25 +02:00
|
|
|
ReturnType::Default => (quote!(#krate::NoContent), true),
|
2019-10-05 14:56:51 +02:00
|
|
|
ReturnType::Type(_, ty) => (quote!(#ty), false)
|
2019-10-05 00:21:41 +02:00
|
|
|
};
|
2020-01-14 23:16:31 +01:00
|
|
|
|
2020-01-22 16:53:02 +00:00
|
|
|
// some default idents we'll need
|
2020-01-14 23:16:31 +01:00
|
|
|
let state_ident = format_ident!("state");
|
2020-01-22 16:53:02 +00:00
|
|
|
let repo_ident = format_ident!("repo");
|
|
|
|
let conn_ident = format_ident!("conn");
|
|
|
|
let auth_ident = format_ident!("auth");
|
|
|
|
|
|
|
|
// extract arguments into pattern, ident and type
|
2020-04-08 22:07:33 +02:00
|
|
|
let mut args : Vec<MethodArgument> = Vec::new();
|
|
|
|
let mut errors : Vec<Error> = Vec::new();
|
|
|
|
for (i, arg) in fun.sig.inputs.iter().enumerate()
|
|
|
|
{
|
|
|
|
let a = match arg {
|
|
|
|
FnArg::Typed(arg) => interpret_arg(i, arg),
|
|
|
|
FnArg::Receiver(_) => Err(Error::new(arg.span(), "Didn't expect self parameter"))
|
|
|
|
};
|
|
|
|
match a {
|
|
|
|
Ok(a) => args.push(a),
|
|
|
|
Err(e) => errors.push(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !errors.is_empty()
|
|
|
|
{
|
|
|
|
let mut iter = errors.into_iter();
|
|
|
|
let first = iter.nth(0).unwrap();
|
|
|
|
return Err(iter.fold(first, |mut e0, e1| { e0.combine(e1); e0 }));
|
|
|
|
}
|
2020-01-14 23:16:31 +01:00
|
|
|
|
|
|
|
// extract the generic parameters to use
|
2020-04-11 19:20:30 +02:00
|
|
|
let ty_names = method.type_names();
|
|
|
|
let ty_len = ty_names.len();
|
|
|
|
let generics_args : Vec<&MethodArgument> = args.iter()
|
2020-01-22 16:53:02 +00:00
|
|
|
.filter(|arg| (*arg).ty.is_method_arg())
|
2020-04-11 19:20:30 +02:00
|
|
|
.collect();
|
|
|
|
if generics_args.len() > ty_len
|
|
|
|
{
|
|
|
|
return Err(Error::new(generics_args[ty_len].span(), "Too many arguments"));
|
|
|
|
}
|
|
|
|
else if generics_args.len() < ty_len
|
|
|
|
{
|
|
|
|
return Err(Error::new(fun_ident.span(), "Too few arguments"));
|
|
|
|
}
|
|
|
|
let generics : Vec<TokenStream2> = generics_args.iter()
|
2020-01-22 16:53:02 +00:00
|
|
|
.map(|arg| arg.ty.quote_ty().unwrap())
|
2020-04-11 19:20:30 +02:00
|
|
|
.zip(ty_names)
|
2020-04-06 16:20:08 +00:00
|
|
|
.map(|(arg, name)| {
|
|
|
|
let ident = format_ident!("{}", name);
|
|
|
|
quote!(type #ident = #arg;)
|
|
|
|
})
|
2020-01-22 16:53:02 +00:00
|
|
|
.collect();
|
2020-01-14 23:16:31 +01:00
|
|
|
|
|
|
|
// extract the definition of our method
|
2020-01-14 23:32:16 +01:00
|
|
|
let mut args_def : Vec<TokenStream2> = args.iter()
|
2020-01-22 16:53:02 +00:00
|
|
|
.filter(|arg| (*arg).ty.is_method_arg())
|
|
|
|
.map(|arg| {
|
|
|
|
let ident = &arg.ident;
|
|
|
|
let ty = arg.ty.quote_ty();
|
|
|
|
quote!(#ident : #ty)
|
|
|
|
}).collect();
|
|
|
|
args_def.insert(0, quote!(#state_ident : &mut #krate::export::State));
|
2020-01-14 23:16:31 +01:00
|
|
|
|
|
|
|
// extract the arguments to pass over to the supplied method
|
2020-01-22 16:53:02 +00:00
|
|
|
let args_pass : Vec<TokenStream2> = args.iter().map(|arg| match (&arg.ty, &arg.ident) {
|
|
|
|
(MethodArgumentType::StateRef, _) => quote!(#state_ident),
|
|
|
|
(MethodArgumentType::StateMutRef, _) => quote!(#state_ident),
|
|
|
|
(MethodArgumentType::MethodArg(_), ident) => quote!(#ident),
|
|
|
|
(MethodArgumentType::DatabaseConnection(_), _) => quote!(&#conn_ident),
|
2020-01-24 17:52:53 +01:00
|
|
|
(MethodArgumentType::AuthStatus(_), _) => quote!(#auth_ident),
|
|
|
|
(MethodArgumentType::AuthStatusRef(_), _) => quote!(&#auth_ident)
|
2020-01-14 23:16:31 +01:00
|
|
|
}).collect();
|
|
|
|
|
|
|
|
// prepare the method block
|
2020-01-22 16:53:02 +00:00
|
|
|
let mut block = quote!(#fun_ident(#(#args_pass),*));
|
|
|
|
if is_no_content
|
2020-01-14 03:27:49 +01:00
|
|
|
{
|
2020-01-22 16:53:02 +00:00
|
|
|
block = quote!(#block; Default::default())
|
|
|
|
}
|
|
|
|
if let Some(arg) = args.iter().filter(|arg| (*arg).ty.is_database_conn()).nth(0)
|
|
|
|
{
|
|
|
|
let conn_ty = arg.ty.quote_ty();
|
2020-01-14 03:27:49 +01:00
|
|
|
block = quote! {
|
2020-01-22 16:53:02 +00:00
|
|
|
let #repo_ident = <#krate::export::Repo<#conn_ty>>::borrow_from(&#state_ident).clone();
|
2020-01-14 23:32:16 +01:00
|
|
|
#repo_ident.run::<_, #ret, ()>(move |#conn_ident| {
|
2020-01-14 23:48:14 +01:00
|
|
|
Ok({#block})
|
2020-01-14 23:32:16 +01:00
|
|
|
}).wait().unwrap()
|
2020-01-14 03:27:49 +01:00
|
|
|
};
|
|
|
|
}
|
2020-01-22 16:53:02 +00:00
|
|
|
if let Some(arg) = args.iter().filter(|arg| (*arg).ty.is_auth_status()).nth(0)
|
|
|
|
{
|
|
|
|
let auth_ty = arg.ty.quote_ty();
|
|
|
|
block = quote! {
|
2020-01-24 17:52:53 +01:00
|
|
|
let #auth_ident : #auth_ty = <#auth_ty>::borrow_from(#state_ident).clone();
|
2020-01-22 16:53:02 +00:00
|
|
|
#block
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// prepare the where clause
|
2020-04-07 20:44:02 +00:00
|
|
|
let mut where_clause = quote!(#resource_path : #krate::Resource,);
|
2020-01-25 14:04:26 +01:00
|
|
|
for arg in args.iter().filter(|arg| (*arg).ty.is_auth_status())
|
2020-01-22 16:53:02 +00:00
|
|
|
{
|
|
|
|
let auth_ty = arg.ty.quote_ty();
|
|
|
|
where_clause = quote!(#where_clause #auth_ty : Clone,);
|
|
|
|
}
|
2019-10-05 00:21:41 +02:00
|
|
|
|
2020-04-11 18:13:36 +00:00
|
|
|
// attribute generated code
|
2020-04-07 20:44:02 +00:00
|
|
|
let operation_id = expand_operation_id(&method_attrs);
|
2020-04-11 18:13:36 +00:00
|
|
|
let wants_auth = expand_wants_auth(&method_attrs, args.iter().any(|arg| (*arg).ty.is_auth_status()));
|
2020-04-07 20:44:02 +00:00
|
|
|
|
2020-01-22 16:53:02 +00:00
|
|
|
// put everything together
|
2020-04-08 22:07:33 +02:00
|
|
|
Ok(quote! {
|
2019-10-27 20:44:23 +00:00
|
|
|
#fun
|
|
|
|
|
2020-04-06 16:20:08 +00:00
|
|
|
#fun_vis mod #mod_ident
|
2019-10-05 00:21:41 +02:00
|
|
|
{
|
2020-04-06 16:20:08 +00:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
struct #handler_ident;
|
|
|
|
|
|
|
|
impl #krate::ResourceMethod for #handler_ident
|
|
|
|
{
|
|
|
|
type Res = #ret;
|
2020-04-07 20:44:02 +00:00
|
|
|
|
|
|
|
#operation_id
|
2020-04-11 18:13:36 +00:00
|
|
|
#wants_auth
|
2020-04-06 16:20:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl #krate::#trait_ident for #handler_ident
|
|
|
|
where #where_clause
|
2019-10-05 14:56:51 +02:00
|
|
|
{
|
2020-04-06 16:20:08 +00:00
|
|
|
#(#generics)*
|
2020-01-22 16:53:02 +00:00
|
|
|
|
2020-04-06 16:20:08 +00:00
|
|
|
fn #method_ident(#(#args_def),*) -> #ret
|
|
|
|
{
|
|
|
|
#[allow(unused_imports)]
|
|
|
|
use #krate::export::{Future, FromState};
|
|
|
|
|
|
|
|
#block
|
|
|
|
}
|
2019-10-05 14:56:51 +02:00
|
|
|
}
|
2020-04-06 16:20:08 +00:00
|
|
|
|
|
|
|
#[deny(dead_code)]
|
|
|
|
pub fn #setup_ident<D : #krate::DrawResourceRoutes>(route : &mut D)
|
|
|
|
{
|
|
|
|
route.#method_ident::<#handler_ident>();
|
|
|
|
}
|
|
|
|
|
2019-10-06 15:03:30 +02:00
|
|
|
}
|
2020-04-08 22:07:33 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand_method(method : Method, attrs : TokenStream, item : TokenStream) -> TokenStream
|
|
|
|
{
|
|
|
|
expand(method, attrs, item)
|
|
|
|
.unwrap_or_else(|err| err.to_compile_error())
|
|
|
|
.into()
|
2019-10-05 00:21:41 +02:00
|
|
|
}
|