Skip to main content

axum_route/
lib.rs

1use proc_macro::{TokenStream, Span};
2use syn::{parse_macro_input, ItemFn};
3use syn::punctuated::Punctuated;
4use syn::parse::{Parse, ParseStream};
5use quote::quote;
6
7struct Args {
8    vars: Vec<syn::Expr>
9}
10
11impl Parse for Args {
12    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
13        let vars = Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated(input)?;
14        
15        Ok(Args {
16            vars: vars.into_iter().collect(),
17        })
18    }
19}
20
21impl Args {
22    pub fn get_method(&self) -> syn::Result<syn::Expr> {
23        match self.vars.get(0) {
24            Some(var) => Ok(var.clone()),
25            None => return Err(syn::Error::new(
26                Span::call_site().into(),
27                "No HTTP Method was provided"
28            ))
29        }
30    }
31    
32    pub fn get_route(&self) -> syn::Result<syn::Expr> {
33        match self.vars.get(1) {
34            Some(var) => Ok(var.clone()),
35            None => return Err(syn::Error::new(
36                Span::call_site().into(),
37                "No Route was provided"
38            ))
39        }
40    }
41}
42
43#[proc_macro_attribute]
44pub fn route(args: TokenStream, input: TokenStream) -> TokenStream {
45    let args = parse_macro_input!(args as Args);
46    let func = parse_macro_input!(input as ItemFn);
47    
48    let vis = func.vis.clone();
49    let ident = func.sig.ident.clone();
50    
51    let method = args.get_method().unwrap();
52    let route = args.get_route().unwrap();
53    
54    let expanded = quote! {
55        #[allow(non_camel_case_types)]
56        #vis struct #ident;
57        
58        impl #ident {
59            #vis fn route() -> axum::Router {
60                #func
61                
62                axum::Router::new().route(#route, #method (#ident))
63            }
64        }
65    };
66    
67    expanded.into()
68}