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())); static EVENTS: Lazy<Mutex<HashMap<String, Vec<(String, String)>>>> = Lazy::new(|| Mutex::new(HashMap::new())); static DEFAULT_INTERS: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(vec![]));
48
49#[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 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 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 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.append_exports(#ident_name, #exports_names_tokens, #is_global_tokens);
264
265 #interceptor_register_tokens
267
268 #controller_register_tokens
269
270 #service_register_tokens
271 #imports_register_tokens
274 #services_dep_inject_tokens
277
278 #controller_dep_inject_tokens
279
280 #interceptor_dep_inject_tokens
281 #trigger_on_module_init_tokens
285 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#[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 main_tokens = TokenStream2::from(quote! {
526 #func
527 });
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 expanded = quote! {
548 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}