Skip to main content

nidrs_macro/
lib.rs

1#![allow(warnings, unused)]
2#![feature(proc_macro_span)]
3extern crate proc_macro;
4
5use std::{
6    any::Any,
7    borrow::BorrowMut,
8    cell::RefCell,
9    collections::HashMap,
10    f64::consts::E,
11    ops::Add,
12    path,
13    str::FromStr,
14    sync::{Arc, Mutex},
15};
16
17use cmeta::CMetaValue;
18use nidrs_extern::{datasets::ServiceType, helper::merge_derives};
19use once_cell::sync::Lazy;
20use proc_macro::{Ident, Span, TokenStream};
21use proc_macro2::TokenStream as TokenStream2;
22use proc_macro2::{Punct, TokenTree};
23use quote::{quote, ToTokens};
24use syn::{
25    meta,
26    parse::{Parse, ParseStream},
27    parse_str, Expr, ExprArray, ItemStruct, PatPath, Stmt, Token,
28};
29use syn::{parse, punctuated::Punctuated};
30use syn::{parse_macro_input, spanned::Spanned, ItemFn};
31
32mod args_parse;
33use args_parse::*;
34use syn_args::{def, SynArgs};
35use utils::merge_uses;
36
37mod app_parse;
38mod args;
39mod cmeta;
40mod current_module;
41mod impl_expand;
42mod import_path;
43mod utils;
44
45static ROUTES: Lazy<Mutex<HashMap<String, Vec<String>>>> = Lazy::new(|| Mutex::new(HashMap::new())); // HashMap<ControllerName, Vec<RouteName>>
46static EVENTS: Lazy<Mutex<HashMap<String, Vec<(String, String)>>>> = Lazy::new(|| Mutex::new(HashMap::new())); // HashMap<EventName, Vec<(ServiceName,FName)>>
47static DEFAULT_INTERS: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(vec![]));
48
49// #[proc_macro_attribute]
50// pub fn test(args: TokenStream, input: TokenStream) -> TokenStream {
51//     let input2 = TokenStream2::from(input.clone());
52//     let func = parse_macro_input!(input as UFnStruct);
53//     println!("test {}", func.ident.to_string());
54//     return TokenStream::from(quote! {
55//         #[nidrs::macros::__test]
56//         #input2
57//     });
58// }
59
60// #[proc_macro_attribute]
61// pub fn __test(args: TokenStream, input: TokenStream) -> TokenStream {
62//     let input2 = input.clone();
63//     let func = parse_macro_input!(input as UFnStruct);
64//     println!("__test {}", func.ident.to_string());
65//     return input2;
66// }
67
68#[proc_macro_attribute]
69pub fn get(args: TokenStream, input: TokenStream) -> TokenStream {
70    return impl_expand::route("get", args, input);
71}
72
73#[proc_macro_attribute]
74pub fn post(args: TokenStream, input: TokenStream) -> TokenStream {
75    return impl_expand::route("post", args, input);
76}
77
78#[proc_macro_attribute]
79pub fn put(args: TokenStream, input: TokenStream) -> TokenStream {
80    return impl_expand::route("put", args, input);
81}
82
83#[proc_macro_attribute]
84pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream {
85    return impl_expand::route("delete", args, input);
86}
87
88#[proc_macro_attribute]
89pub fn any(args: TokenStream, input: TokenStream) -> TokenStream {
90    return impl_expand::route("any", args, input);
91}
92
93#[proc_macro_attribute]
94pub fn head(args: TokenStream, input: TokenStream) -> TokenStream {
95    return impl_expand::route("head", args, input);
96}
97
98#[proc_macro_attribute]
99pub fn on(args: TokenStream, input: TokenStream) -> TokenStream {
100    return impl_expand::route("on", args, input);
101}
102
103#[proc_macro_attribute]
104pub fn options(args: TokenStream, input: TokenStream) -> TokenStream {
105    return impl_expand::route("options", args, input);
106}
107
108#[proc_macro_attribute]
109pub fn patch(args: TokenStream, input: TokenStream) -> TokenStream {
110    return impl_expand::route("patch", args, input);
111}
112
113#[proc_macro_attribute]
114pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream {
115    return impl_expand::route("trace", args, input);
116}
117
118#[proc_macro_attribute]
119pub fn __route_derive(args: TokenStream, input: TokenStream) -> TokenStream {
120    return impl_expand::route_derive(args, input);
121}
122
123#[syn_args::derive::declare(def::Option<def::String>)]
124#[syn_args::derive::proc_attribute]
125pub fn controller(args: Args, input: TokenStream) -> TokenStream {
126    let path = match args {
127        Args::F1(def::Option(Some(v))) => v.to_string(),
128        _ => "".to_string(),
129    };
130
131    current_module::begin_mod();
132
133    let func = parse_macro_input!(input as ItemStruct);
134
135    let ident = func.ident.clone();
136    let ident_name = ident.to_string();
137
138    import_path::push_path(&func.ident.to_string());
139
140    ROUTES.lock().expect("Failed to lock ROUTES in controller macro").insert(ident.to_string(), Vec::new());
141
142    TokenStream::from(quote! {
143        #[nidrs::meta(nidrs::datasets::ServiceType::from("Controller"))]
144        #[nidrs::meta(nidrs::datasets::ServiceName::from(#ident_name))]
145        #[nidrs::meta(nidrs::datasets::ControllerPath::from(#path))]
146        #[nidrs::macros::__service_derive(Controller)]
147        #func
148    })
149}
150
151#[proc_macro_attribute]
152pub fn injectable(args: TokenStream, input: TokenStream) -> TokenStream {
153    current_module::begin_mod();
154    let func = parse_macro_input!(input as ItemStruct);
155    let func_ident = func.ident.clone();
156    let func_ident_name = func.ident.to_string();
157
158    let call_site = Span::call_site();
159    let binding = call_site.source_file().path();
160    let call_site_str = binding.to_string_lossy();
161    let call_site_line = call_site.start().line();
162
163    // println!("// injectable {}", func.ident.to_string());
164    import_path::push_path(&func_ident_name.clone());
165
166    return TokenStream::from(quote! {
167        #[nidrs::meta(nidrs::datasets::ServiceType::from("Service"))]
168        #[nidrs::meta(nidrs::datasets::ServiceName::from(#func_ident_name))]
169        #[nidrs::macros::__service_derive(Service)]
170        #func
171    });
172}
173
174#[proc_macro_attribute]
175pub fn interceptor(args: TokenStream, input: TokenStream) -> TokenStream {
176    current_module::begin_mod();
177    let func = parse_macro_input!(input as ItemStruct);
178    let func_ident = func.ident.clone();
179    let func_ident_name = func.ident.to_string();
180
181    import_path::push_path(&func_ident_name.clone());
182
183    return TokenStream::from(quote! {
184        #[nidrs::meta(nidrs::datasets::ServiceType::from("Interceptor"))]
185        #[nidrs::meta(nidrs::datasets::ServiceName::from(#func_ident_name))]
186        #[nidrs::macros::__service_derive(Interceptor)]
187        #func
188    });
189}
190
191#[syn_args::derive::declare(def::Expr)]
192#[syn_args::derive::proc_attribute]
193pub fn __service_derive(args: Args, input: TokenStream) -> TokenStream {
194    let service_type = match args {
195        Args::F1(v) => match v.to_path_name().expect("Failed to get path name in __service_derive").as_str() {
196            "Controller" => ServiceType::Controller,
197            "Service" => ServiceType::Service,
198            "Interceptor" => ServiceType::Interceptor,
199            _ => panic!("Invalid service type"),
200        },
201    };
202    impl_expand::__service_derive(service_type, input)
203}
204
205#[syn_args::derive::declare(args::ModuleOptions)]
206#[syn_args::derive::proc_attribute]
207pub fn __module_derive(args: Args, input: TokenStream) -> TokenStream {
208    // 解析宏的参数
209    let module_options: args::ModuleOptions = {
210        if let Args::F1(options) = args {
211            options
212        } else {
213            panic!("Invalid argument");
214        }
215    };
216
217    let func = parse_macro_input!(input as ItemStruct);
218    let (impl_generics, ty_generics, where_clause) = func.generics.split_for_impl();
219    let ident = func.ident.clone();
220    let ident_name = ident.to_string();
221
222    let controller_register_tokens = impl_expand::expand_controller_register(ident_name.clone(), &module_options.controllers);
223    let service_register_tokens = impl_expand::expand_service_register(ident_name.clone(), &module_options.services);
224
225    let all_interceptors = impl_expand::merge_defaults_interceptors(module_options.interceptors.clone());
226    let interceptor_register_tokens = impl_expand::expand_interceptor_register(ident_name.clone(), &all_interceptors);
227    let (import_names_tokens, imports_register_tokens) = impl_expand::expand_imports_register(ident_name.clone(), &module_options.imports, &func);
228    // let imports_register_names = args.imports.clone().iter().map(|import_tokens| import_tokens.to_string()).collect::<Vec<String>>();
229    let exports_names_tokens = impl_expand::expand_exports_append(&module_options.exports);
230
231    let services_dep_inject_tokens: TokenStream2 = impl_expand::expand_dep_inject("get_service", ident_name.clone(), &module_options.services);
232    let controller_dep_inject_tokens = impl_expand::expand_dep_inject("get_controller", ident_name.clone(), &module_options.controllers);
233    let interceptor_dep_inject_tokens = impl_expand::expand_dep_inject("get_interceptor", ident_name.clone(), &module_options.interceptors);
234
235    let trigger_on_module_init_tokens: TokenStream2 = impl_expand::expand_events_trigger(ident_name.clone(), "on_module_init");
236    let trigger_on_module_destroy_tokens = impl_expand::expand_events_trigger(ident_name.clone(), "on_module_destroy");
237
238    let module_meta_tokens = cmeta::CMeta::build_tokens();
239    let is_global_tokens = if let Some(CMetaValue::Bool(bool)) = cmeta::CMeta::get_stack_data("Global") { bool } else { false };
240    println!("// module {:?}", ident.to_string());
241    {
242        ROUTES.lock().expect("Failed to lock ROUTES in module derive").clear();
243        EVENTS.lock().expect("Failed to lock EVENTS in module derive").clear();
244    }
245    current_module::end_mod();
246
247    let derives_tokens: Vec<TokenStream2> = merge_derives(&func, &["Default"]);
248
249    return TokenStream::from(quote! {
250        #(#derives_tokens)*
251        #func
252
253        impl #impl_generics nidrs::Module for #ident #ty_generics #where_clause  {
254            fn init(self, mut ctx: nidrs::ModuleCtx) -> nidrs::ModuleCtx{
255                use nidrs::{Service, Controller, Interceptor, InterCtx, InterceptorHandler, ModuleCtx, StateCtx, ImplMeta};
256                if ctx.modules.contains_key(#ident_name) {
257                    return ctx;
258                }
259                nidrs_macro::log!("Registering module {}.", #ident_name);
260                ctx.modules.insert(#ident_name.to_string(), Box::new(self));
261                ctx.imports.insert(#ident_name.to_string(), #import_names_tokens);
262                // ctx.exports.insert(#module_name.to_string(), #exports_names_tokens);
263                ctx.append_exports(#ident_name, #exports_names_tokens, #is_global_tokens);
264
265                // {
266                    #interceptor_register_tokens
267
268                    #controller_register_tokens
269
270                    #service_register_tokens
271                // }
272                // {
273                    #imports_register_tokens
274                // }
275                // {
276                    #services_dep_inject_tokens
277
278                    #controller_dep_inject_tokens
279
280                    #interceptor_dep_inject_tokens
281                // }
282
283                // {
284                    #trigger_on_module_init_tokens
285                // }
286
287                ctx
288            }
289
290            fn destroy(&self, ctx: &nidrs::ModuleCtx){
291                #trigger_on_module_destroy_tokens
292                nidrs::log!("Destroying module {}.", #ident_name);
293            }
294        }
295
296        impl #impl_generics nidrs::ImplMeta for #ident #ty_generics #where_clause{
297            fn __meta(&self) -> nidrs::InnerMeta {
298                #module_meta_tokens
299            }
300        }
301    });
302}
303
304#[proc_macro_attribute]
305pub fn module(args: TokenStream, input: TokenStream) -> TokenStream {
306    let input2 = TokenStream2::from(input);
307    let args2 = TokenStream2::from(args);
308
309    TokenStream::from(quote! {
310        #[nidrs::macros::meta(__ = true)]
311        #[nidrs::macros::__module_derive(#args2)]
312        #input2
313    })
314}
315
316#[proc_macro_attribute]
317pub fn on_module_init(args: TokenStream, input: TokenStream) -> TokenStream {
318    let func = parse_macro_input!(input as ItemFn);
319
320    let ident = func.sig.ident.clone();
321    let name = ident.to_string();
322
323    let current_service_name: String =
324        cmeta::CMeta::get_stack_data("ServiceName").expect(&format!("[on_module_init] {} ServiceName not found", name));
325
326    EVENTS
327        .lock()
328        .expect("Failed to lock EVENTS in on_module_init")
329        .entry("on_module_init".to_string())
330        .or_insert(vec![])
331        .push((current_service_name, name));
332
333    return TokenStream::from(quote! {
334        #func
335    });
336}
337
338#[proc_macro_attribute]
339pub fn on_module_destroy(args: TokenStream, input: TokenStream) -> TokenStream {
340    let func = parse_macro_input!(input as ItemFn);
341
342    let ident = func.sig.ident.clone();
343    let name = ident.to_string();
344
345    let current_service_name: String =
346        cmeta::CMeta::get_stack_data("ServiceName").expect(&format!("[on_module_init] {} ServiceName not found", name));
347
348    EVENTS
349        .lock()
350        .expect("Failed to lock EVENTS in on_module_destroy")
351        .entry("on_module_destroy".to_string())
352        .or_insert(vec![])
353        .push((current_service_name, name));
354
355    return TokenStream::from(quote! {
356        #func
357    });
358}
359
360#[syn_args::derive::declare(def::Expr, def::Extends<def::Expr>)]
361#[syn_args::derive::proc_attribute]
362pub fn uses(args: Args, input: TokenStream) -> TokenStream {
363    let args: Vec<def::Expr> = match args {
364        Args::F1(first, other) => {
365            let mut args = vec![first];
366            args.append(&mut other.clone());
367            args
368        }
369        _ => panic!("Invalid argument"),
370    };
371    let raw = TokenStream2::from(input.clone());
372    let func = parse_macro_input!(input as UFnStruct);
373    let used_ident = &func.ident;
374    let inter_names = args.iter().map(|arg| arg.to_path_name().expect("Failed to get path name in uses macro")).collect::<Vec<String>>();
375
376    let expand = match &func.typ {
377        TokenType::Fn(item) => {
378            quote! {
379                #[nidrs::meta(method_uses = [#(#inter_names),*])]
380            }
381        }
382        TokenType::Struct(item) => {
383            quote! {
384                #[nidrs::meta(service_uses = [#(#inter_names),*])]
385            }
386        }
387        _ => panic!("Invalid argument"),
388    };
389
390    return quote! {
391        #expand
392        #raw
393    }
394    .into();
395}
396
397// #[syn_args::derive::declare(def::Expr, def::Extends<def::Expr>)]
398// #[syn_args::derive::proc_attribute]
399// pub fn default_uses(args: Args, input: TokenStream) -> TokenStream {
400//     let args: Vec<def::Expr> = match args {
401//         Args::F1(first, other) => {
402//             let mut args = vec![first];
403//             args.append(&mut other.clone());
404//             args
405//         }
406//         _ => panic!("Invalid argument"),
407//     };
408//     let inter_names = args.iter().map(|arg| arg.to_path_name().unwrap()).collect::<Vec<String>>();
409
410//     DEFAULT_INTERS.lock().unwrap().append(&mut inter_names.clone());
411
412//     return input;
413// }
414
415#[proc_macro_attribute]
416pub fn meta(args: TokenStream, input: TokenStream) -> TokenStream {
417    let raw: TokenStream = input.clone();
418    let fun = parse_macro_input!(input as UFnStruct);
419
420    current_module::check_mod();
421
422    let level = cmeta::CMeta::get_level();
423
424    if let None = level {
425        cmeta::init_app_meta();
426        cmeta::init_module_meta();
427    }
428
429    let level = cmeta::CMeta::get_level();
430
431    if let TokenType::Struct(item) = &fun.typ {
432        let cur_mod = current_module::get();
433        if let Some(cur_mod) = cur_mod {
434            let level_mod = cmeta::CMeta::get_stack("module");
435            if let Some(cmeta::CMetaValue::String(name)) = &level_mod {
436                if &cur_mod.name != name {
437                    let deep = cmeta::CMeta::get_deep();
438                    let loop_deep = deep - 1;
439                    for _ in 0..loop_deep {
440                        cmeta::CMeta::pop();
441                    }
442
443                    cmeta::CMeta::push(cmeta::CMetaLevel::Module(cur_mod.name.clone()));
444                    cmeta::CMeta::push(cmeta::CMetaLevel::Service(item.ident.to_string()));
445                }
446            }
447        }
448
449        let level = cmeta::CMeta::get_level();
450        if let Some(cmeta::CMetaLevel::Service(name)) = level {
451            if item.ident.to_string() != name {
452                cmeta::CMeta::pop();
453                cmeta::CMeta::push(cmeta::CMetaLevel::Service(item.ident.to_string()));
454            }
455        } else if let Some(cmeta::CMetaLevel::Handler(name)) = level {
456            cmeta::CMeta::pop();
457            cmeta::CMeta::pop();
458            cmeta::CMeta::push(cmeta::CMetaLevel::Service(item.ident.to_string()));
459        } else {
460            cmeta::CMeta::push(cmeta::CMetaLevel::Service(item.ident.to_string()));
461        }
462    } else if let TokenType::Fn(item) = &fun.typ {
463        if let Some(cmeta::CMetaLevel::Handler(name)) = level {
464            if item.sig.ident.to_string() != name {
465                cmeta::CMeta::pop();
466                cmeta::CMeta::push(cmeta::CMetaLevel::Handler(item.sig.ident.to_string()));
467            }
468        } else {
469            cmeta::CMeta::push(cmeta::CMetaLevel::Handler(item.sig.ident.to_string()));
470        }
471    }
472
473    let targs = args.clone();
474    let cmeta = parse_macro_input!(targs as cmeta::CMeta);
475    cmeta::CMeta::collect(cmeta);
476
477    return raw;
478}
479
480#[syn_args::derive::declare(def::String)]
481#[syn_args::derive::proc_attribute]
482pub fn version(args: Args, input: TokenStream) -> TokenStream {
483    let version = match args {
484        Args::F1(v) => v.to_string(),
485        _ => "".to_string(),
486    };
487
488    let input = TokenStream2::from(input);
489    return TokenStream::from(quote! {
490        #[nidrs::macros::meta(version = #version)]
491        #input
492    });
493}
494
495#[proc_macro_attribute]
496pub fn disable_default_prefix(args: TokenStream, input: TokenStream) -> TokenStream {
497    let raw_input = TokenStream2::from(input.clone());
498
499    return TokenStream::from(quote! {
500        #[nidrs::macros::meta(nidrs::datasets::DisableDefaultPrefix::from(true))]
501        #raw_input
502    });
503}
504
505#[proc_macro_attribute]
506pub fn global(args: TokenStream, input: TokenStream) -> TokenStream {
507    let raw_input = TokenStream2::from(input.clone());
508
509    return TokenStream::from(quote! {
510        #[nidrs::macros::meta(nidrs::datasets::Global::from(true))]
511        #raw_input
512    });
513}
514
515#[proc_macro_attribute]
516pub fn main(args: TokenStream, input: TokenStream) -> TokenStream {
517    cmeta::CMeta::pop();
518    let func = parse_macro_input!(input as ItemFn);
519    let ident = func.sig.ident.clone();
520
521    // let import_mod_tokens = import_path::gen_import_mod_tokens();
522
523    // println!("main {:?} {}", func.sig.ident.to_string(), import_mod_tokens.to_string());
524
525    let main_tokens = TokenStream2::from(quote! {
526        #func
527        // #import_mod_tokens
528    });
529
530    return main_tokens.into();
531}
532
533#[proc_macro]
534pub fn throw(input: TokenStream) -> TokenStream {
535    let input = TokenStream2::from(input);
536    let call_site = Span::call_site();
537    let binding = call_site.source_file().path();
538    let call_site_str = binding.to_string_lossy();
539    let call_site_line = call_site.start().line();
540
541    // let binding = ROUTES.lock().unwrap();
542    // let current_controller = CURRENT_CONTROLLER.lock().unwrap();
543    // let struct_name =  current_controller.as_ref().unwrap().name.clone();
544    // let method_name = binding.get(&struct_name).unwrap().keys().last().unwrap();
545
546    // 构建返回的 TokenStream
547    let expanded = quote! {
548        // println!("Macro called from method: {}.{}", stringify!(#struct_name), stringify!(#method_name));
549        // println!("Macro called from: {} line {}", #call_site_str, #call_site_line);
550        nidrs::__throw(#input, &format!("from {} line {}", #call_site_str, #call_site_line))?;
551    };
552
553    expanded.into()
554}
555
556#[proc_macro]
557pub fn log(input: TokenStream) -> TokenStream {
558    let input = TokenStream2::from(input);
559
560    let input_tokens = input.into_iter().collect::<Vec<_>>();
561
562    return TokenStream::from(quote::quote! {
563        print!("{} ", nidrs_extern::colored::Colorize::green("[nidrs]"));
564        println!(#(#input_tokens)*);
565    });
566}
567
568#[proc_macro]
569pub fn elog(input: TokenStream) -> TokenStream {
570    let input = TokenStream2::from(input);
571
572    let input_tokens = input.into_iter().collect::<Vec<_>>();
573
574    return TokenStream::from(quote::quote! {
575        eprint!("{} ", nidrs_extern::colored::Colorize::red("[nidrs]"));
576        eprintln!(#(#input_tokens)*);
577    });
578}