变更宏路由实现
This commit is contained in:
parent
44bbc846df
commit
2ea3813a32
@ -1,6 +1,6 @@
|
||||
use axum::routing::MethodRouter;
|
||||
|
||||
type TypedHandler<S = ()> = fn() -> (&'static str, MethodRouter<S>);
|
||||
type TypedHandler<S = ()> = fn() -> Vec<(&'static str, MethodRouter<S>)>;
|
||||
|
||||
/// A trait that allows typed routes, created with the [`route`] macro to
|
||||
/// be added to an axum router.
|
||||
@ -25,9 +25,10 @@ where
|
||||
S: Send + Sync + Clone + 'static,
|
||||
{
|
||||
type State = S;
|
||||
|
||||
fn typed_route(self, handler: TypedHandler<Self::State>) -> Self {
|
||||
let (path, method_router) = handler();
|
||||
self.route(path, method_router)
|
||||
let routes = handler();
|
||||
routes.into_iter().fold(self, |router, (path, method_router)| {
|
||||
router.route(path, method_router)
|
||||
})
|
||||
}
|
||||
}
|
@ -23,45 +23,45 @@ pub fn responsable(input: TokenStream) -> TokenStream {
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
route::gen_route(attr, item)
|
||||
route::gen_route(attr, item, "route")
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
route::gen_dyn_route(attr, item, "get")
|
||||
route::gen_route(attr, item, "get")
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
route::gen_dyn_route(attr, item, "post")
|
||||
route::gen_route(attr, item, "post")
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn put(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
route::gen_dyn_route(attr, item, "put")
|
||||
route::gen_route(attr, item, "put")
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn patch(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
route::gen_dyn_route(attr, item, "patch")
|
||||
route::gen_route(attr, item, "patch")
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn delete(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
route::gen_dyn_route(attr, item, "delete")
|
||||
route::gen_route(attr, item, "delete")
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn options(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
route::gen_dyn_route(attr, item, "options")
|
||||
route::gen_route(attr, item, "options")
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn head(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
route::gen_dyn_route(attr, item, "head")
|
||||
route::gen_route(attr, item, "head")
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn trace(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
route::gen_dyn_route(attr, item, "trace")
|
||||
route::gen_route(attr, item, "trace")
|
||||
}
|
@ -5,14 +5,89 @@ extern crate syn;
|
||||
extern crate proc_macro;
|
||||
|
||||
use parse::{Parse, ParseStream};
|
||||
use proc_macro::{Span, TokenStream}; use punctuated::Punctuated;
|
||||
use proc_macro::{Span, TokenStream};
|
||||
use punctuated::Punctuated;
|
||||
// 用于处理宏输入
|
||||
use quote::quote; use spanned::Spanned;
|
||||
use quote::quote;
|
||||
use spanned::Spanned;
|
||||
// 用于生成代码
|
||||
use syn::*;
|
||||
use syn::{parse_macro_input, ItemFn};
|
||||
|
||||
struct RouteArgs {
|
||||
path: String,
|
||||
methods: Vec<String>,
|
||||
}
|
||||
|
||||
// 实现 Parse trait 以支持解析参数
|
||||
impl Parse for RouteArgs {
|
||||
fn parse(input: ParseStream) -> syn::parse::Result<Self> {
|
||||
// 使用Meta解析 begin
|
||||
// let args = Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated(input)?;
|
||||
// let mut path = None;
|
||||
// let mut methods = Vec::new();
|
||||
// for arg in args {
|
||||
// if let Meta::NameValue(nv) = arg {
|
||||
// if nv.path.is_ident("method") {
|
||||
// if let Expr::Array(ExprArray { elems, .. }) = nv.value {
|
||||
// for elem in elems {
|
||||
// if let Expr::Lit(syn::ExprLit { lit: Lit::Str(lit_str), .. }) = elem {
|
||||
// methods.push(lit_str.value());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else if nv.path.is_ident("path") {
|
||||
// if let Expr::Lit(ExprLit { lit: Lit::Str(lit_str), .. }) = nv.value {
|
||||
// path = Some(lit_str.value());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// let path = path.expect("Expected a path argument");
|
||||
// 使用Meta解析 end
|
||||
|
||||
let args = Punctuated::<syn::Expr, syn::Token![,]>::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),
|
||||
..
|
||||
}) => {
|
||||
path = Some(lit_str.value());
|
||||
}
|
||||
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.expect("路由参数不能为空");
|
||||
|
||||
Ok(RouteArgs { path, methods })
|
||||
}
|
||||
}
|
||||
|
||||
struct Args {
|
||||
vars: Vec<syn::Expr>
|
||||
vars: Vec<syn::Expr>,
|
||||
}
|
||||
|
||||
impl Parse for Args {
|
||||
@ -32,52 +107,54 @@ impl Args {
|
||||
None => {
|
||||
// 第一个参数使路由url,必须存在,其他的参数根据实际需求进一步解析
|
||||
if index != 0 {
|
||||
return Ok(None)
|
||||
return Ok(None);
|
||||
} else {
|
||||
return Err(syn::Error::new(
|
||||
Span::call_site().into(),
|
||||
"route must have one argument"
|
||||
))
|
||||
"route must have one argument",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn gen_route(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let args = parse_macro_input!(attr as Args);
|
||||
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 method = args.get_arg(0).unwrap();
|
||||
let route = args.get_arg(1).unwrap();
|
||||
let mut method_routers = Vec::new();
|
||||
if methods.is_empty() {
|
||||
let method_name = syn::Ident::new(&method.to_lowercase(), method.span());
|
||||
method_routers.push(quote! {
|
||||
(#path, axum::routing::#method_name(#ident))
|
||||
});
|
||||
} else {
|
||||
for method in methods {
|
||||
let method_name = syn::Ident::new(&method.to_lowercase(), method.span());
|
||||
method_routers.push(quote! {
|
||||
(#path, axum::routing::#method_name(#ident))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let expanded = quote! {
|
||||
#[allow(non_camel_case_types)]
|
||||
#vis struct #ident;
|
||||
let generated = quote! {
|
||||
#vis fn #ident () -> Vec<(&'static str, axum::routing::method_routing::MethodRouter)> {
|
||||
#func
|
||||
|
||||
impl #ident {
|
||||
#vis fn route() -> axum::Router {
|
||||
#func
|
||||
|
||||
axum::Router::new().route(#route, #method (#ident))
|
||||
}
|
||||
vec![#(#method_routers),*]
|
||||
}
|
||||
};
|
||||
|
||||
expanded.into()
|
||||
TokenStream::from(generated)
|
||||
}
|
||||
|
||||
/// todo
|
||||
///
|
||||
/// 计划采用
|
||||
/// ```#[route("path"), methods = [Get, Post]]```
|
||||
/// 的形式进行完善,使方法支持多种网络请求
|
||||
///
|
||||
/// gen_dyn_route 生成的代码不再是的单独的MethodRouter,而是MethodRouter集合
|
||||
#[allow(dead_code)]
|
||||
pub fn gen_dyn_route(attr: TokenStream, item: TokenStream, method: &str) -> TokenStream {
|
||||
let args = parse_macro_input!(attr as Args);
|
||||
let func = parse_macro_input!(item as ItemFn);
|
||||
@ -87,6 +164,26 @@ pub fn gen_dyn_route(attr: TokenStream, item: TokenStream, method: &str) -> Toke
|
||||
|
||||
let route = args.get_arg(0).unwrap().unwrap();
|
||||
|
||||
let method_option = args.get_arg(1);
|
||||
match method_option {
|
||||
Ok(method) => {
|
||||
if let Some(Expr::Assign(methods_value)) = method {
|
||||
println!("method is {:?}", methods_value);
|
||||
// if let Expr::Path(left) = methods_value.left {
|
||||
// left.path.segments[0].ident.eq("d") {
|
||||
|
||||
// }
|
||||
// }
|
||||
// if let Expr::Lit(right) = methods_value.right {
|
||||
|
||||
// }
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
println!("error is {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let method_name: Ident = Ident::new(method, route.span());
|
||||
|
||||
let expanded = quote! {
|
||||
@ -97,4 +194,4 @@ pub fn gen_dyn_route(attr: TokenStream, item: TokenStream, method: &str) -> Toke
|
||||
}
|
||||
};
|
||||
expanded.into()
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use library::extractor::path_extractor::PathVar;
|
||||
use library::model::response::ResResult;
|
||||
use library::extractor::body_extractor::JsonBody;
|
||||
use library::extractor::query_extractor::QueryParams;
|
||||
use macros::{get, post};
|
||||
use macros::{get, post, route};
|
||||
|
||||
use crate::service;
|
||||
|
||||
@ -35,7 +35,7 @@ pub async fn get_feedback_list_by_page(
|
||||
.await
|
||||
}
|
||||
|
||||
#[get("/feedback/:page/:pageSize", d = "a")]
|
||||
#[route("/feedback/:page/:pageSize", method = ["get", "post"])]
|
||||
pub async fn get_feedback_list(
|
||||
context: Context,
|
||||
PathVar(page_params): PathVar<PageParams>,
|
||||
|
@ -5,7 +5,7 @@ pub mod account_controller;
|
||||
pub mod feedback_controller;
|
||||
|
||||
pub fn init() -> Router {
|
||||
Router::new()
|
||||
let mut app = Router::new()
|
||||
// 用户登录、用户管理相关路由
|
||||
.typed_route(account_controller::authenticate_google)
|
||||
.typed_route(account_controller::authenticate_with_password)
|
||||
@ -13,5 +13,10 @@ pub fn init() -> Router {
|
||||
// 反馈相关路由
|
||||
.typed_route(feedback_controller::add_feedback)
|
||||
.typed_route(feedback_controller::get_feedback_list_by_page)
|
||||
.typed_route(feedback_controller::get_feedback_list)
|
||||
// .typed_route(feedback_controller::get_feedback_list)
|
||||
;
|
||||
for (path, method_router) in feedback_controller::get_feedback_list() {
|
||||
app = app.route(path, method_router);
|
||||
}
|
||||
app
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user