use proc_macro::TokenStream;
use quote::quote;
use syn::{
parse::{Parse, ParseStream},
parse_macro_input, ItemFn, LitStr,
};
#[derive(Debug, Clone, Copy)]
pub enum HttpMethod {
Get,
Post,
Put,
Delete,
Patch,
}
impl HttpMethod {
#[allow(dead_code)]
fn axum_method(&self) -> proc_macro2::TokenStream {
match self {
HttpMethod::Get => quote! { get },
HttpMethod::Post => quote! { post },
HttpMethod::Put => quote! { put },
HttpMethod::Delete => quote! { delete },
HttpMethod::Patch => quote! { patch },
}
}
#[allow(dead_code)]
fn as_str(&self) -> &'static str {
match self {
HttpMethod::Get => "GET",
HttpMethod::Post => "POST",
HttpMethod::Put => "PUT",
HttpMethod::Delete => "DELETE",
HttpMethod::Patch => "PATCH",
}
}
}
pub struct RouteArgs {
path: LitStr,
}
impl Parse for RouteArgs {
fn parse(input: ParseStream) -> syn::Result<Self> {
let path: LitStr = input.parse()?;
Ok(RouteArgs { path })
}
}
pub fn expand_route_macro(
method: HttpMethod,
args: TokenStream,
input: TokenStream,
) -> TokenStream {
let args = parse_macro_input!(args as RouteArgs);
let path = args.path;
let func = parse_macro_input!(input as ItemFn);
let func_name = &func.sig.ident;
let func_vis = &func.vis;
let route_helper_name = syn::Ident::new(&format!("__{}_route", func_name), func_name.span());
let method_str = method.as_str();
let expanded = quote! {
#func
#[allow(non_upper_case_globals)]
#func_vis const #route_helper_name: (&'static str, &'static str) = (#path, #method_str);
};
TokenStream::from(expanded)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_http_method_as_str() {
assert_eq!(HttpMethod::Get.as_str(), "GET");
assert_eq!(HttpMethod::Post.as_str(), "POST");
assert_eq!(HttpMethod::Put.as_str(), "PUT");
assert_eq!(HttpMethod::Delete.as_str(), "DELETE");
assert_eq!(HttpMethod::Patch.as_str(), "PATCH");
}
}