route handler macro accepts idents

This commit is contained in:
realaravinth 2021-05-13 19:22:44 +05:30
parent f277b128b6
commit 0b61bd6b0b
No known key found for this signature in database
GPG Key ID: AD9F0F08E855ED88
2 changed files with 49 additions and 4 deletions

View File

@ -77,16 +77,23 @@ impl TryFrom<&syn::LitStr> for MethodType {
} }
struct Args { struct Args {
path: syn::LitStr, //path: Option<syn::LitStr>,
path: Box<dyn PathMarker>,
// i_path: Option<syn::Ident>,
resource_name: Option<syn::LitStr>, resource_name: Option<syn::LitStr>,
guards: Vec<Ident>, guards: Vec<Ident>,
wrappers: Vec<syn::Type>, wrappers: Vec<syn::Type>,
methods: HashSet<MethodType>, methods: HashSet<MethodType>,
} }
trait PathMarker: quote::ToTokens {}
impl PathMarker for syn::Ident {}
impl PathMarker for syn::LitStr {}
impl Args { impl Args {
fn new(args: AttributeArgs, method: Option<MethodType>) -> syn::Result<Self> { fn new(args: AttributeArgs, method: Option<MethodType>) -> syn::Result<Self> {
let mut path = None; let mut path: Option<Box<dyn PathMarker>> = None;
let mut resource_name = None; let mut resource_name = None;
let mut guards = Vec::new(); let mut guards = Vec::new();
let mut wrappers = Vec::new(); let mut wrappers = Vec::new();
@ -101,8 +108,9 @@ impl Args {
match arg { match arg {
NestedMeta::Lit(syn::Lit::Str(lit)) => match path { NestedMeta::Lit(syn::Lit::Str(lit)) => match path {
None => { None => {
path = Some(lit); path = Some(Box::new(lit));
} }
_ => { _ => {
return Err(syn::Error::new_spanned( return Err(syn::Error::new_spanned(
lit, lit,
@ -120,6 +128,31 @@ impl Args {
"Attribute name expects literal string!", "Attribute name expects literal string!",
)); ));
} }
} else if nv.path.is_ident("path") {
if let syn::Lit::Str(lit) = nv.lit {
// path = Some(syn::LitStr::new(
// &Ident::new(&lit.value(), Span::call_site()).to_string(),
// Span::call_site(),
// ));
match path {
None => {
let x = Ident::new(&lit.value(), Span::call_site());
path = Some(Box::new(x));
}
_ => {
return Err(syn::Error::new_spanned(
lit,
"Multiple paths specified! Should be only one!",
));
}
}
} else {
return Err(syn::Error::new_spanned(
nv.lit,
"Attribute path expects literal string!",
));
}
} else if nv.path.is_ident("guard") { } else if nv.path.is_ident("guard") {
if let syn::Lit::Str(lit) = nv.lit { if let syn::Lit::Str(lit) = nv.lit {
guards.push(Ident::new(&lit.value(), Span::call_site())); guards.push(Ident::new(&lit.value(), Span::call_site()));
@ -173,6 +206,7 @@ impl Args {
} }
} }
} }
Ok(Args { Ok(Args {
path: path.unwrap(), path: path.unwrap(),
resource_name, resource_name,
@ -318,6 +352,8 @@ impl ToTokens for Route {
} }
}; };
let path = path.as_ref();
let stream = quote! { let stream = quote! {
#(#doc_attributes)* #(#doc_attributes)*
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
@ -337,7 +373,6 @@ impl ToTokens for Route {
} }
} }
}; };
output.extend(stream); output.extend(stream);
} }
} }

View File

@ -19,6 +19,12 @@ async fn config() -> impl Responder {
HttpResponse::Ok() HttpResponse::Ok()
} }
const PATH: &str = "/path";
#[get(path = "PATH")]
async fn path() -> impl Responder {
HttpResponse::Ok()
}
#[get("/test")] #[get("/test")]
async fn test_handler() -> impl Responder { async fn test_handler() -> impl Responder {
HttpResponse::Ok() HttpResponse::Ok()
@ -158,7 +164,11 @@ async fn test_params() {
.service(get_param_test) .service(get_param_test)
.service(put_param_test) .service(put_param_test)
.service(delete_param_test) .service(delete_param_test)
.service(path)
}); });
let request = srv.request(http::Method::GET, srv.url(PATH));
let response = request.send().await.unwrap();
assert_eq!(response.status(), http::StatusCode::OK);
let request = srv.request(http::Method::GET, srv.url("/test/it")); let request = srv.request(http::Method::GET, srv.url("/test/it"));
let response = request.send().await.unwrap(); let response = request.send().await.unwrap();