use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{ItemFn, LitStr};
pub fn route_macro(
http_method: &str,
axum_fn: &str,
attr: TokenStream,
item: TokenStream,
) -> TokenStream {
let path: LitStr = match syn::parse2(attr) {
Ok(path) => path,
Err(err) => return err.to_compile_error(),
};
if path.value().is_empty() {
return syn::Error::new(path.span(), "Route path must not be empty").to_compile_error();
}
if !path.value().starts_with('/') {
let suggested = format!("/{}", path.value());
return syn::Error::new(
path.span(),
format!("Route path must start with '/'. Did you mean \"{suggested}\"?"),
)
.to_compile_error();
}
let input_fn: ItemFn = match syn::parse2(item.clone()) {
Ok(f) => f,
Err(_) => {
return syn::Error::new_spanned(item, "route macros can only be applied to functions")
.to_compile_error();
}
};
if input_fn.sig.asyncness.is_none() {
return syn::Error::new_spanned(
input_fn.sig.fn_token,
"Autumn route handlers must be async functions",
)
.to_compile_error();
}
let fn_name = &input_fn.sig.ident;
let route_info_name = format_ident!("__autumn_route_info_{}", fn_name);
let vis = &input_fn.vis;
let method_const = format_ident!("{}", http_method); let routing_fn = format_ident!("{}", axum_fn);
quote! {
#input_fn
#[doc(hidden)]
#vis fn #route_info_name() -> ::autumn_web::route::Route {
::autumn_web::route::Route {
method: ::autumn_web::reexports::http::Method::#method_const,
path: #path,
handler: ::autumn_web::reexports::axum::routing::#routing_fn(#fn_name),
name: ::core::stringify!(#fn_name),
}
}
}
}