use std::ops::Deref;
use proc_macro::TokenStream;
use quote::quote;
use syn::parse_macro_input;
#[proc_macro_attribute]
pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
let item_fn: syn::ItemFn = syn::parse(item).unwrap();
let args = parse_macro_input!(attr as syn::AttributeArgs);
let sig = item_fn.sig;
let name = sig.ident.clone();
let body = item_fn.block.deref();
let path_token = args[0].clone();
let return_type = sig.output;
let body_args = sig.inputs;
let is_body_args = !body_args.is_empty();
let mut path;
match path_token {
syn::NestedMeta::Meta(_) => panic!("IN TOKEN MATCH!"),
syn::NestedMeta::Lit(e) => match e {
syn::Lit::Str(e) => {
path = e.value();
}
syn::Lit::ByteStr(_) => panic!("IN TOKEN MATCH!"),
syn::Lit::Byte(_) => panic!("IN TOKEN MATCH!"),
syn::Lit::Char(_) => panic!("IN TOKEN MATCH!"),
syn::Lit::Int(_) => panic!("IN TOKEN MATCH!"),
syn::Lit::Float(_) => panic!("IN TOKEN MATCH!"),
syn::Lit::Bool(_) => panic!("IN TOKEN MATCH!"),
syn::Lit::Verbatim(_) => panic!("IN TOKEN MATCH!"),
},
};
let new_wildcard = if path.contains("/:") {
let path_clone = path.clone();
let mut iter = path_clone.split(':');
path = iter.next().unwrap().to_string();
let id = iter.next().unwrap().to_string();
if path.len() != 1 {
path.pop();
};
quote! {get_route = get_route.set_wildcard(#id.into());}
} else {
quote! {}
};
#[allow(unused_assignments)]
let mut return_type_str = String::new();
match return_type {
syn::ReturnType::Default => return_type_str = "NO RETURN TYPE!".to_string(),
syn::ReturnType::Type(_, value) => match *value {
syn::Type::Path(stream) => {
return_type_str = stream.path.segments.last().unwrap().ident.to_string()
}
_ => return_type_str = "NO RETURN TYPE!".to_string(),
},
};
let is_ret_type_res = return_type_str == "Response";
let new_get_body = if is_ret_type_res {
quote! {
let mut get_route = GetRouteWithReqAndRes::new()
.set_path(#path.into());
fn body(#body_args) -> Response {
#body.into()
}
get_route = get_route.set_body(body);
}
} else if is_body_args {
quote! {
let mut get_route = GetRouteWithReq::new()
.set_path(#path.into());
fn body(#body_args) -> Vec<u8> {
#body.into()
}
get_route = get_route.set_body(body);
}
} else {
quote! {
let mut get_route = BasicGetRoute::new()
.set_path(#path.into());
fn body() -> Vec<u8> {
#body.into()
}
get_route = get_route.set_body(body);
}
};
let output = quote! {
fn #name() -> Box<dyn Route> {
#new_get_body
#new_wildcard
Box::new(get_route)
}
};
output.into()
}
#[proc_macro_attribute]
pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
let args = parse_macro_input!(attr as syn::AttributeArgs);
let item: syn::ItemFn = syn::parse(item).unwrap();
let fn_args = item.sig.inputs;
let name = item.sig.ident.clone();
let body = item.block.deref();
let return_type = item.sig.output;
let path_token = args[0].clone();
let is_body_args = !fn_args.is_empty();
let mut path;
match path_token {
syn::NestedMeta::Meta(_) => panic!("IN MATCH RETURN TYPE!"),
syn::NestedMeta::Lit(e) => match e {
syn::Lit::Str(e) => {
path = e.value();
}
syn::Lit::ByteStr(_) => panic!("IN MATCH RETURN TYPE!"),
syn::Lit::Byte(_) => panic!("IN MATCH RETURN TYPE!"),
syn::Lit::Char(_) => panic!("IN MATCH RETURN TYPE!"),
syn::Lit::Int(_) => panic!("IN MATCH RETURN TYPE!"),
syn::Lit::Float(_) => panic!("IN MATCH RETURN TYPE!"),
syn::Lit::Bool(_) => panic!("IN MATCH RETURN TYPE!"),
syn::Lit::Verbatim(_) => panic!("IN MATCH RETURN TYPE!"),
},
};
let new_wildcard = if path.contains("/:") {
let path_clone = path.clone();
let mut iter = path_clone.split(':');
path = iter.next().unwrap().to_string();
let id = iter.next().unwrap().to_string();
if path.len() != 1 {
path.pop();
};
quote! {post_route = post_route.set_wildcard(#id.into());}
} else {
quote! {}
};
#[allow(unused_assignments)]
let mut return_type_str = String::new();
match return_type {
syn::ReturnType::Default => return_type_str = "NO RETURN TYPE!".to_string(),
syn::ReturnType::Type(_, value) => match *value {
syn::Type::Path(stream) => {
return_type_str = stream.path.segments.last().unwrap().ident.to_string()
}
_ => return_type_str = "NO RETURN TYPE!".to_string(),
},
};
let is_ret_type_res = return_type_str == "Response";
let new_post_body = if is_ret_type_res {
quote! {
let mut post_route = PostRouteWithReqAndRes::new()
.set_path(#path.into());
fn body(#fn_args) -> Response {
#body.into()
}
post_route = post_route.set_body(body);
}
} else if is_body_args {
quote! {
let mut post_route = PostRouteWithReq::new()
.set_path(#path.into());
fn body(#fn_args) -> Vec<u8> {
#body.into()
}
post_route = post_route.set_body(body);
}
} else {
quote! {
let mut post_route = BasicPostRoute::new()
.set_path(#path.into());
fn body() -> Vec<u8> {
#body.into()
}
post_route = post_route.set_body(body);
}
};
let output = quote! {
fn #name() -> Box<dyn Route> {
#new_post_body
#new_wildcard
Box::new(post_route)
}
};
output.into()
}