extern crate proc_macro2; extern crate quote; extern crate syn; extern crate proc_macro; use parse::{Parse, ParseStream}; use proc_macro::{Span, TokenStream}; use punctuated::Punctuated; // 用于处理宏输入 use quote::quote; use spanned::Spanned; // 用于生成代码 use syn::*; use syn::{parse_macro_input, ItemFn}; struct RouteArgs { path: String, methods: Vec, } // 实现 Parse trait 以支持解析参数 impl Parse for RouteArgs { fn parse(input: ParseStream) -> Result { let args = Punctuated::::parse_terminated(input)?; let mut path = None; let mut methods = Vec::new(); for expr in args { match expr { Expr::Lit(ExprLit { lit: Lit::Str(lit_str), .. }) => { let path_str = lit_str.value(); // 验证路由路径 validate_route_path(&path_str)?; path = Some(path_str); } Expr::Assign(assign) => { if let Expr::Path(path) = *assign.left { if path.path.is_ident("method") { if let Expr::Array(ExprArray { elems, .. }) = *assign.right { for elem in elems { if let Expr::Lit(ExprLit { lit: Lit::Str(lit_str), .. }) = elem { methods.push(lit_str.value()); } } } } } } _ => {} } } let path = path.ok_or_else(|| Error::new( Span::call_site().into(), "路由路径参数不能为空", ))?; Ok(RouteArgs { path, methods }) } } // 添加路由参数验证 fn validate_route_path(path: &str) -> Result<()> { if !path.starts_with('/') { return Err(Error::new( Span::call_site().into(), "路由路径必须以'/'开头", )); } Ok(()) } pub fn gen_route(attr: TokenStream, item: TokenStream, method: &str) -> TokenStream { let func = parse_macro_input!(item as ItemFn); // 解析宏的参数 let RouteArgs { path, methods } = parse_macro_input!(attr as RouteArgs); // 将 method 转换为小写并生成标识符 // let vis = func.vis.clone(); let ident = func.sig.ident.clone(); let mut method_routers = Vec::new(); if methods.is_empty() { let method_name = Ident::new(&method.to_lowercase(), method.span()); method_routers.push(quote! { (#path, axum::routing::#method_name(#ident::#ident)) }); } else { for method in methods { let method_name = Ident::new(&method.to_lowercase(), method.span()); method_routers.push(quote! { (#path, axum::routing::#method_name(#ident::#ident)) }); } } let generated = quote! { #[allow(non_camel_case_types)] struct #ident; impl #ident { #func } impl library::typed_router::RouteMethod for #ident { fn ge_router(&self, mut router: axum::Router) -> axum::Router { let methods = vec![#(#method_routers),*]; for (path, method_router) in methods { router = router.route(path, method_router); } router } } ::library::submit_router_method!(#ident); }; TokenStream::from(generated) }