use crate::extractor::body::deal_with_body_attr;
use crate::extractor::path::deal_with_path_attr;
use crate::route::{RouteAttr, build_register_expr};
use crate::toolkit::exactors::build_struct_from_query;
use crate::toolkit::rout_arg::{
FnArgResult, IntoFnArgs, RouteFnArg, build_config_value_injector, build_dep_injector,
};
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{ItemFn, Stmt, parse_quote};
pub fn route_handler(args: RouteAttr, mut fn_item: ItemFn) -> TokenStream {
let fn_name = fn_item.sig.ident.clone();
let sig = &mut fn_item.sig;
if matches!(sig.output, syn::ReturnType::Default) {
(*sig).output = parse_quote!(-> impl ::miko::http::response::into_response::IntoResponse)
}
let inject_segs: Vec<Stmt> = Vec::new();
let rfa = RouteFnArg::from_punctuated(&mut sig.inputs);
let path_inputs = rfa.gen_fn_args(deal_with_path_attr);
let body_inputs = rfa.gen_fn_args(deal_with_body_attr);
let plain_inputs = rfa.gen_fn_args(|rfa| {
if rfa.mark.is_empty() {
FnArgResult::Keep
} else {
FnArgResult::Remove
}
});
let mut dep_stmts = Vec::new();
build_dep_injector(&rfa, &mut dep_stmts);
#[cfg(feature = "auto")]
let dep_stmts = if dep_stmts.is_empty() {
dep_stmts
} else {
dep_stmts.insert(
0,
quote! {
let __dep_container = ::miko::dependency_container::get_global_dc().await;
},
);
dep_stmts
};
let mut config_value_stmts = Vec::new();
build_config_value_injector(&rfa, &mut config_value_stmts);
sig.inputs.clear();
sig.inputs.extend(path_inputs);
let q_struct_ident = Ident::new(
&format!("__{}_QueryStruct", fn_name.to_string()),
Span::call_site(),
);
let (q_struct, q_struct_exactor) = build_struct_from_query(&rfa, q_struct_ident);
if q_struct.is_some() {
sig.inputs.push(q_struct_exactor.unwrap());
}
sig.inputs.extend(plain_inputs);
sig.inputs.extend(body_inputs);
let user_stmts = &fn_item.block.stmts.clone();
let inventory_collect: Option<proc_macro2::TokenStream> = if cfg!(feature = "auto") {
Some(build_register_expr(&args, &fn_name.clone()))
} else {
None
};
quote! {
#q_struct
#sig {
#(#inject_segs)*
#(#dep_stmts)*
#(#config_value_stmts)*
#(#user_stmts)*
}
#inventory_collect
}
.into()
}