1mod attribute;
2mod parse;
3mod rule;
4use std::str::FromStr;
5
6use attribute::AttributeValue;
7use proc_macro::TokenStream;
8use quote::ToTokens;
9use syn::Expr;
10
11const SHARP: &str = "#";
12
13#[proc_macro_attribute]
14#[allow(non_snake_case)]
15pub fn Module(attr: TokenStream, mut item: TokenStream) -> TokenStream {
16 let _item = item.clone();
17 let ast = syn::parse_macro_input!(_item as syn::ItemStruct);
18
19 let struct_name = parse::find_struct_name(&ast);
20
21 let attribute_map: std::collections::HashMap<String, attribute::AttributeValue> =
22 attribute::parse_attribute(attr.clone(), false);
23
24 let controllers = match attribute_map.get("controllers") {
25 Some(controllers) => match controllers {
26 attribute::AttributeValue::ListOfString(controllers) => controllers.to_owned(),
27 attribute::AttributeValue::String(controller) => vec![controller.to_owned()],
28 },
29 None => vec![],
30 };
31
32 let modules = match attribute_map.get("modules") {
33 Some(modules) => match modules {
34 attribute::AttributeValue::ListOfString(modules) => modules.to_owned(),
35 AttributeValue::String(module) => vec![module.to_owned()],
36 },
37 None => vec![],
38 };
39
40 let providers = match attribute_map.get("providers") {
41 Some(providers) => match providers {
42 attribute::AttributeValue::ListOfString(providers) => providers.to_owned(),
43 AttributeValue::String(provider) => vec![provider.to_owned()],
44 },
45 None => vec![],
46 };
47
48 let middlewares = match attribute_map.get("middlewares") {
49 Some(middlewares) => match middlewares {
50 AttributeValue::ListOfString(middlewares) => middlewares.to_owned(),
51 AttributeValue::String(middleware) => vec![middleware.to_owned()],
52 },
53 None => vec![],
54 };
55
56 let controllers = controllers
57 .iter()
58 .map(|controller| format!("Box::new({})", controller.to_owned()))
59 .collect::<Vec<String>>()
60 .join(", ");
61
62 let modules = modules
63 .iter()
64 .map(|module| format!("Box::new({})", module.to_owned()))
65 .collect::<Vec<String>>()
66 .join(", ");
67
68 let providers = providers
69 .iter()
70 .map(|provider| format!("Box::new({})", provider.to_owned()))
71 .collect::<Vec<String>>()
72 .join(", ");
73
74 let middlewares = middlewares
75 .iter()
76 .map(|middleware| format!("Box::new({})", middleware.to_owned()))
77 .collect::<Vec<String>>()
78 .join(", ");
79
80 let new_code = format!(
81 r#"impl rupring::IModule for {struct_name} {{
82 fn child_modules(&self) -> Vec<Box<dyn rupring::IModule>> {{
83 vec![{modules}]
84 }}
85
86 fn controllers(&self) -> Vec<Box<dyn rupring::IController>> {{
87 vec![{controllers}]
88 }}
89
90 fn providers(&self) -> Vec<Box<dyn rupring::IProvider>> {{
91 vec![{providers}]
92 }}
93
94 fn middlewares(&self) -> Vec<rupring::MiddlewareFunction> {{
95 vec![{middlewares}]
96 }}
97}}
98"#
99 );
100
101 item.extend(TokenStream::from_str(new_code.as_str()).unwrap());
102
103 return item;
104}
105
106#[proc_macro_attribute]
107#[allow(non_snake_case)]
108pub fn Controller(attr: TokenStream, mut item: TokenStream) -> TokenStream {
109 let _item = item.clone();
110 let ast = syn::parse_macro_input!(_item as syn::ItemStruct);
111
112 let struct_name = parse::find_struct_name(&ast);
113
114 let attribute_map = attribute::parse_attribute(attr.clone(), false);
115
116 let prefix = match attribute_map.get("prefix") {
117 Some(prefix) => match prefix {
118 AttributeValue::String(prefix) => prefix.to_owned(),
119 _ => "".to_string(),
120 },
121 None => "".to_string(),
122 };
123
124 let routes = match attribute_map.get("routes") {
125 Some(routes) => match routes {
126 AttributeValue::ListOfString(routes) => routes.to_owned(),
127 AttributeValue::String(route) => vec![route.to_owned()],
128 },
129 None => vec![],
130 };
131
132 let routes = routes
133 .iter()
134 .map(|route| {
135 let mut scopes = route.split("::").map(|e| e.trim()).collect::<Vec<&str>>();
136
137 let route = scopes.pop().unwrap();
138
139 let route_name = rule::make_route_name(route);
140
141 let scopes = scopes.join("::");
142
143 if scopes.len() > 0 {
144 format!("Box::new({scopes}::{route_name}{{}})")
145 } else {
146 format!("Box::new({route_name}{{}})")
147 }
148 })
149 .collect::<Vec<String>>()
150 .join(", ");
151
152 let middlewares = match attribute_map.get("middlewares") {
153 Some(middlewares) => match middlewares {
154 AttributeValue::ListOfString(middlewares) => middlewares.to_owned(),
155 AttributeValue::String(middleware) => vec![middleware.to_owned()],
156 },
157 None => vec![],
158 };
159
160 let middlewares = middlewares
161 .iter()
162 .map(|middleware| format!("Box::new({})", middleware.to_owned()))
163 .collect::<Vec<String>>()
164 .join(", ");
165
166 let new_code = format!(
167 r#"impl rupring::IController for {struct_name} {{
168 fn prefix(&self) -> String {{
169 "{prefix}".to_string()
170 }}
171
172 fn routes(&self) -> Vec<Box<dyn rupring::IRoute + Send + 'static>> {{
173 vec![{routes}]
174 }}
175
176 fn middlewares(&self) -> Vec<rupring::MiddlewareFunction> {{
177 vec![{middlewares}]
178 }}
179 }}"#
180 );
181
182 item.extend(TokenStream::from_str(new_code.as_str()).unwrap());
183
184 return item;
185}
186
187#[proc_macro_attribute]
188#[allow(non_snake_case)]
189pub fn Service(attr: TokenStream, item: TokenStream) -> TokenStream {
190 return Injectable(attr, item);
191}
192
193#[proc_macro_attribute]
194#[allow(non_snake_case)]
195pub fn Repository(attr: TokenStream, item: TokenStream) -> TokenStream {
196 return Injectable(attr, item);
197}
198
199#[proc_macro_attribute]
200#[allow(non_snake_case)]
201pub fn Component(attr: TokenStream, item: TokenStream) -> TokenStream {
202 return Injectable(attr, item);
203}
204
205#[proc_macro_attribute]
206#[allow(non_snake_case)]
207pub fn Bean(attr: TokenStream, item: TokenStream) -> TokenStream {
208 return Injectable(attr, item);
209}
210
211#[proc_macro_attribute]
212#[allow(non_snake_case)]
213pub fn Injectable(attr: TokenStream, mut item: TokenStream) -> TokenStream {
214 let _item = item.clone();
215 let function_ast = syn::parse_macro_input!(_item as syn::ItemFn);
216
217 let _provider_type = parse::find_function_return_type(&function_ast);
218 let parameters_types = parse::find_function_parameter_types(&function_ast);
219 let function_name = parse::find_function_name(&function_ast);
220
221 let mut dependencies = vec![];
222 let mut arguments = vec![];
223 for parameter_type in parameters_types {
224 dependencies.push(format!("std::any::TypeId::of::<{parameter_type}>()",));
225
226 if parameter_type.contains("&") {
227 arguments.push(format!("di_context.get::<{parameter_type}>().unwrap()",));
228 } else {
229 arguments.push(format!(
230 "di_context.get::<{parameter_type}>().unwrap().to_owned()"
231 ));
232 }
233 }
234
235 let struct_name = if attr.is_empty() {
236 function_name.clone()
237 } else if attr.clone().into_iter().count() == 1 {
238 attr.into_iter().next().unwrap().to_string()
239 } else {
240 let attribute_map = attribute::parse_attribute(attr.clone(), false);
241
242 match attribute_map.get("name") {
243 Some(name) => match name {
244 AttributeValue::String(name) => name.to_owned(),
245 _ => function_name.clone(),
246 },
247 None => function_name.clone(),
248 }
249 };
250
251 let function_call = format!("{function_name}({})", arguments.join(", "));
252 let dependencies = dependencies.join(", ");
253
254 let new_code = format!(
255 r#"
256#[allow(non_camel_case_types)]
257pub struct {struct_name}{{}}
258impl rupring::IProvider for {struct_name} {{
259 fn dependencies(&self) -> Vec<std::any::TypeId> {{
260 vec![{dependencies}]
261 }}
262
263 fn provide(&self, di_context: &rupring::DIContext) -> Box<dyn std::any::Any> {{
264 Box::new({function_call})
265 }}
266}}"#
267 );
268
269 item.extend(TokenStream::from_str(new_code.as_str()).unwrap());
270
271 return item;
272}
273
274fn convert_rust_type_to_js_type(rust_type: &str) -> String {
275 match rust_type {
276 "i8" | "i16" | "i32" | "i64" | "i128" | "isize" | "u8" | "u16" | "u32" | "u64" | "u128" => {
277 "integer".to_string()
278 }
279 "Option<i8>" | "Option<i16>" | "Option<i32>" | "Option<i64>" | "Option<i128>"
280 | "Option<isize>" | "Option<u8>" | "Option<u16>" | "Option<u32>" | "Option<u64>"
281 | "Option<u128>" => "integer".to_string(),
282 "f32" | "f64" => "number".to_string(),
283 "Option<f32>" | "Option<f64>" => "number".to_string(),
284 "bool" => "boolean".to_string(),
285 "Option<bool>" => "boolean".to_string(),
286 _ => "string".to_string(),
287 }
288}
289
290#[allow(non_snake_case)]
291fn MapRoute(method: String, attr: TokenStream, item: TokenStream) -> TokenStream {
292 let _item = item.clone();
293 let function_ast = syn::parse_macro_input!(_item as syn::ItemFn);
294
295 let (item, additional_attributes) = attribute::extract_additional_attributes(item);
296 let summary = additional_attributes
297 .get("summary")
298 .map(|e| e.as_string())
299 .unwrap_or_default()
300 .trim_start_matches("\"")
301 .trim_end_matches("\"")
302 .to_owned();
303
304 let description = additional_attributes
305 .get("Description")
306 .map(|e| e.as_string())
307 .unwrap_or_default()
308 .trim_start_matches("\"")
309 .trim_end_matches("\"")
310 .to_owned();
311
312 let tags = additional_attributes
313 .get("tags")
314 .map(|e| match e {
315 AttributeValue::ListOfString(tags) => tags.to_owned(),
316 AttributeValue::String(tag) => vec![tag.to_owned()],
317 })
318 .map(|e| {
319 e.iter()
320 .map(|e| e.trim_start_matches("\"").trim_end_matches("\"").to_owned())
321 .collect::<Vec<_>>()
322 })
323 .unwrap_or_default();
324
325 let tags = format!(
326 "vec![{}]",
327 tags.iter()
328 .map(|e| format!("\"{}\".to_string()", e))
329 .collect::<Vec<_>>()
330 .join(", ")
331 );
332
333 let request_body = additional_attributes
334 .get("parameters")
335 .or(additional_attributes.get("params"))
336 .map(|e| e.as_string())
337 .unwrap_or_default()
338 .trim_start_matches("\"")
339 .trim_end_matches("\"")
340 .to_owned();
341
342 let response = additional_attributes
343 .get("response")
344 .map(|e| e.as_string())
345 .unwrap_or_default()
346 .trim_start_matches("\"")
347 .trim_end_matches("\"")
348 .to_owned();
349
350 let auth = additional_attributes.get("auth").map(|e| {
351 let mut auth_value = e
352 .as_string()
353 .trim_start_matches("\"")
354 .trim_end_matches("\"")
355 .to_owned();
356
357 if auth_value.len() == 0 {
358 auth_value = "BearerAuth".to_string();
359 }
360
361 auth_value
362 });
363
364 let (item, annotated_parameters) = parse::manipulate_route_function_parameters(item);
365
366 let mut swagger_code = "".to_string();
367 let mut variables_code = "".to_string();
368
369 for anotated_parameter in annotated_parameters {
372 if anotated_parameter.attributes.contains_key("PathVariable") {
373 let parameter_name = anotated_parameter.name;
374 let parameter_type = anotated_parameter.type_;
375 let path_name = anotated_parameter.attributes["PathVariable"].as_string();
376 let path_name = path_name.trim_start_matches("\"").trim_end_matches("\"");
377 let required = !parameter_type.starts_with("Option<");
378 let type_ = convert_rust_type_to_js_type(parameter_type.as_str());
379
380 let description = anotated_parameter
381 .attributes
382 .get("Description")
383 .map(|e| {
384 e.as_string()
385 .trim_start_matches("\"")
386 .trim_end_matches("\"")
387 .to_string()
388 })
389 .unwrap_or_default();
390
391 let variable_expression = format!(
392 r###"
393 use rupring::ParamStringDeserializer;
394 let ___{parameter_name} = rupring::ParamString(request.path_parameters["{path_name}"].clone());
395 let {parameter_name}: {parameter_type} = match ___{parameter_name}.deserialize() {{
396 Ok(v) => v,
397 Err(_) => return rupring::Response::new().status(400).text("Invalid parameter: {parameter_name}"),
398 }};
399 "###
400 );
401
402 variables_code.push_str(&variable_expression);
403
404 swagger_code.push_str(
405 format!(
406 r##"
407 swagger.parameters.push(
408 rupring::swagger::SwaggerParameter {{
409 name: "{parameter_name}".to_string(),
410 in_: rupring::swagger::SwaggerParameterCategory::Path,
411 description: "{description}".to_string(),
412 required: {required},
413 schema: Some(rupring::swagger::SwaggerTypeOrReference::Type(
414 rupring::swagger::SwaggerType {{
415 type_: "{type_}".to_string(),
416 }}
417 )),
418 type_: None,
419 }}
420 );
421 "##
422 )
423 .as_str(),
424 );
425
426 continue;
427 }
428 }
429
430 let mut item = parse::prepend_code_to_function_body(
431 item,
432 TokenStream::from_str(variables_code.as_str()).unwrap(),
433 );
434
435 let function_name = parse::find_function_name(&function_ast);
436 let attribute_map = attribute::parse_attribute(attr.clone(), false);
437
438 let path = match attribute_map.get("path") {
439 Some(path) => match path {
440 AttributeValue::String(path) => path.to_owned(),
441 _ => "".to_string(),
442 },
443 None => "".to_string(),
444 };
445
446 let route_name = rule::make_route_name(function_name.as_str());
447 let handler_name = rule::make_handler_name(function_name.as_str());
448
449 let mut swagger_request_body_code = "".to_string();
450 if request_body.len() > 0 {
451 swagger_request_body_code = format!(
452 r#"
453 fn swagger_request_info(&self) -> Option<rupring::swagger::macros::SwaggerRequestBody> {{
454 rupring::swagger::macros::generate_swagger_request_info::<{request_body}>()
455 }}
456 "#
457 );
458 }
459
460 let mut swagger_response_body_code = "".to_string();
461 if response.len() > 0 {
462 swagger_response_body_code = format!(
463 r#"
464 fn swagger_response_info(&self) -> Option<rupring::swagger::macros::SwaggerRequestBody> {{
465 rupring::swagger::macros::generate_swagger_request_info::<{response}>()
466 }}
467 "#
468 );
469 }
470
471 let mut swagger_security_code = "".to_string();
472 if let Some(auth) = auth {
473 swagger_security_code = format!(
474 r#"
475 fn swagger_security_info(&self) -> Vec<rupring::swagger::json::SwaggerSecurity> {{
476 vec![
477 std::collections::HashMap::from_iter(vec![("{auth}".to_string(), vec![])])
478 ]
479 }}
480 "#
481 );
482 }
483
484 swagger_code.push_str(format!("swagger.summary = \"{summary}\".to_string();").as_str());
485 swagger_code.push_str(format!("swagger.description = \"{description}\".to_string();").as_str());
486 swagger_code.push_str(format!("swagger.tags = {tags};", tags = tags).as_str());
487
488 let new_code = format!(
489 r#"
490#[allow(non_camel_case_types)]
491#[derive(Debug, Clone)]
492pub(crate) struct {route_name} {{}}
493
494impl rupring::IRoute for {route_name} {{
495 fn method(&self) -> rupring::Method {{
496 rupring::Method::{method}
497 }}
498
499 fn path(&self) -> String {{
500 "{path}".to_string()
501 }}
502
503 fn handler(&self) -> Box<dyn rupring::IHandler + Send + 'static> {{
504 Box::new({handler_name}{{}})
505 }}
506
507 fn swagger(&self) -> rupring::swagger::SwaggerOperation {{
508 let mut swagger = rupring::swagger::SwaggerOperation::default();
509 {swagger_code}
510 swagger
511 }}
512
513 {swagger_request_body_code}
514
515 {swagger_response_body_code}
516
517 {swagger_security_code}
518}}
519
520#[allow(non_camel_case_types)]
521#[derive(Debug, Clone)]
522pub(crate) struct {handler_name}{{}}
523
524impl rupring::IHandler for {handler_name} {{
525 fn handle(&self, request: rupring::Request, response: rupring::Response) -> rupring::Response {{
526 {function_name}(request, response)
527 }}
528}}
529"#,
530 );
531
532 item.extend(TokenStream::from_str(new_code.as_str()).unwrap());
533
534 return item;
535}
536
537#[proc_macro_attribute]
538#[allow(non_snake_case)]
539pub fn Get(attr: TokenStream, item: TokenStream) -> TokenStream {
540 return MapRoute("GET".to_string(), attr, item);
541}
542
543#[proc_macro_attribute]
544#[allow(non_snake_case)]
545pub fn GetMapping(attr: TokenStream, item: TokenStream) -> TokenStream {
546 return Get(attr, item);
547}
548
549#[proc_macro_attribute]
550#[allow(non_snake_case)]
551pub fn Post(attr: TokenStream, item: TokenStream) -> TokenStream {
552 return MapRoute("POST".to_string(), attr, item);
553}
554
555#[proc_macro_attribute]
556#[allow(non_snake_case)]
557pub fn PostMapping(attr: TokenStream, item: TokenStream) -> TokenStream {
558 return Post(attr, item);
559}
560
561#[proc_macro_attribute]
562#[allow(non_snake_case)]
563pub fn Put(attr: TokenStream, item: TokenStream) -> TokenStream {
564 return MapRoute("PUT".to_string(), attr, item);
565}
566
567#[proc_macro_attribute]
568#[allow(non_snake_case)]
569pub fn PutMapping(attr: TokenStream, item: TokenStream) -> TokenStream {
570 return Put(attr, item);
571}
572
573#[proc_macro_attribute]
574#[allow(non_snake_case)]
575pub fn Delete(attr: TokenStream, item: TokenStream) -> TokenStream {
576 return MapRoute("DELETE".to_string(), attr, item);
577}
578
579#[proc_macro_attribute]
580#[allow(non_snake_case)]
581pub fn DeleteMapping(attr: TokenStream, item: TokenStream) -> TokenStream {
582 return Delete(attr, item);
583}
584
585#[proc_macro_attribute]
586#[allow(non_snake_case)]
587pub fn Patch(attr: TokenStream, item: TokenStream) -> TokenStream {
588 return MapRoute("PATCH".to_string(), attr, item);
589}
590
591#[proc_macro_attribute]
592#[allow(non_snake_case)]
593pub fn PatchMapping(attr: TokenStream, item: TokenStream) -> TokenStream {
594 return Patch(attr, item);
595}
596
597#[proc_macro_derive(
614 RupringDto,
615 attributes(
616 example,
617 description,
618 desc,
619 required,
620 name,
621 path_param,
622 param,
623 query,
624 body,
625 ignore,
626 )
627)]
628pub fn derive_rupring_dto(item: TokenStream) -> TokenStream {
629 let ast = syn::parse_macro_input!(item as syn::ItemStruct);
630 let struct_name = parse::find_struct_name(&ast);
631
632 let mut code = "".to_string();
633
634 code +=
635 format!(r#"impl rupring::swagger::macros::ToSwaggerDefinitionNode for {struct_name} {{"#)
636 .as_str();
637
638 code += "fn get_definition_name() -> String {";
639 code += r#"let current_module_name = module_path!().to_string();"#;
640 code += format!(r#"let definition_name = format!("{{current_module_name}}::{struct_name}");"#)
641 .as_str();
642 code += "definition_name";
643 code += "}";
644
645 code += "fn to_swagger_definition(context: &mut rupring::swagger::macros::SwaggerDefinitionContext) -> rupring::swagger::macros::SwaggerDefinitionNode {";
646 code += format!(r#"let mut swagger_definition = rupring::swagger::json::SwaggerDefinition {{"#)
647 .as_str();
648 code += format!(r#"type_: "object".to_string(),"#).as_str();
649 code += format!(r#"properties: std::collections::HashMap::new(),"#).as_str();
650 code += format!(r#"required: vec![],"#).as_str();
651 code += format!(r#"path_parameters: vec![],"#).as_str();
652 code += format!(r#"query_parameters: vec![],"#).as_str();
653 code += "};";
654
655 let mut define_struct_for_json = "".to_string();
656 define_struct_for_json += format!("#[allow(non_camel_case_types)]").as_str();
657 define_struct_for_json +=
658 format!(r#"#[derive(serde::Serialize, serde::Deserialize)]"#).as_str();
659 define_struct_for_json += format!(r#"pub struct {struct_name}__JSON {{"#).as_str();
660
661 let mut json_field_names = vec![];
662 let mut path_field_names = vec![];
663 let mut query_field_names = vec![];
664
665 for field in ast.fields.iter() {
666 let mut description = "".to_string();
667 let mut example = r#""""#.to_string();
668
669 let field_name = field.ident.as_ref().unwrap().to_string();
670 let mut field_type = field.ty.to_token_stream().to_string().replace(" ", "");
671
672 let struct_field_name = field_name.clone();
673 let mut param_name = field_name.clone();
674
675 let attributes = field.attrs.clone();
676
677 let mut is_required = true;
678 let mut is_ignore = false;
679
680 let mut is_path_parameter = false;
681 let mut is_query_parameter = false;
682
683 if field_type.starts_with("Option<") {
684 is_required = false;
685 }
686
687 for attribute in attributes {
688 let metadata = attribute.meta;
689
690 let path = metadata.path().to_token_stream().to_string();
691
692 let meta_value = metadata.require_name_value().ok().map(|e| e.value.clone());
693
694 match path.to_lowercase().as_str() {
695 "example" => {
696 if let Some(Expr::Lit(lit)) = &meta_value {
697 example = format!("{:?}", lit.to_token_stream().to_string());
698 }
699 }
700 "required" => {
701 if let Some(Expr::Lit(lit)) = &meta_value {
702 is_required = lit.to_token_stream().to_string().parse().unwrap();
703 } else {
704 is_required = true;
705 }
706 }
707 "description" | "desc" => {
708 if let Some(Expr::Lit(lit)) = &meta_value {
709 let mut text = lit.to_token_stream().to_string();
710
711 if text.starts_with("\"") {
712 text = text
713 .trim_start_matches("\"")
714 .trim_end_matches("\"")
715 .to_string();
716 }
717
718 description = text;
719 }
720 }
721 "name" => {
722 if let Some(Expr::Lit(lit)) = &meta_value {
723 let mut text = lit.to_token_stream().to_string();
724
725 if text.starts_with("\"") {
726 text = text
727 .trim_start_matches("\"")
728 .trim_end_matches("\"")
729 .to_string();
730 }
731
732 param_name = text;
733 }
734 }
735 "path_param" | "param" => {
736 if let Some(Expr::Lit(lit)) = &meta_value {
737 let mut text = lit.to_token_stream().to_string();
738
739 if text.starts_with("\"") {
740 text = text
741 .trim_start_matches("\"")
742 .trim_end_matches("\"")
743 .to_string();
744 }
745
746 param_name = text;
747 }
748
749 is_path_parameter = true;
750 }
751 "query" => {
752 is_query_parameter = true;
753
754 if let Some(Expr::Lit(lit)) = &meta_value {
755 let mut text = lit.to_token_stream().to_string();
756
757 if text.starts_with("\"") {
758 text = text
759 .trim_start_matches("\"")
760 .trim_end_matches("\"")
761 .to_string();
762 }
763
764 param_name = text;
765 }
766 }
767 "ignore" => {
768 is_ignore = true;
769 }
770 _ => {}
771 }
772 }
773
774 if is_ignore {
775 continue;
776 }
777
778 if is_required {
779 code += format!(r#"swagger_definition.required.push("{field_name}".to_string());"#)
780 .as_str();
781 }
782
783 if field_type.contains("<") {
785 field_type = field_type.replace("<", "::<")
786 }
787
788 if is_path_parameter {
789 path_field_names.push((
790 struct_field_name.clone(),
791 param_name.clone(),
792 field_type.clone(),
793 ));
794
795 code += format!(
796 r#"swagger_definition.path_parameters.push(rupring::swagger::json::SwaggerParameter {{
797 name: "{field_name}".to_string(),
798 in_: rupring::swagger::json::SwaggerParameterCategory::Path,
799 description: "{description}".to_string(),
800 required: {is_required},
801 schema: Some(rupring::swagger::json::SwaggerTypeOrReference::Type(
802 rupring::swagger::json::SwaggerType {{
803 type_: "{field_type}".to_string(),
804 }}
805 )),
806 type_: None,
807 }});"#
808 ).as_str();
809
810 continue;
811 }
812
813 if is_query_parameter {
814 query_field_names.push((
815 struct_field_name.clone(),
816 param_name.clone(),
817 field_type.clone(),
818 ));
819
820 code += format!(
821 r#"swagger_definition.query_parameters.push(rupring::swagger::json::SwaggerParameter {{
822 name: "{field_name}".to_string(),
823 in_: rupring::swagger::json::SwaggerParameterCategory::Query,
824 description: "{description}".to_string(),
825 required: {is_required},
826 schema: Some(rupring::swagger::json::SwaggerTypeOrReference::Type(
827 rupring::swagger::json::SwaggerType {{
828 type_: "{field_type}".to_string(),
829 }}
830 )),
831 type_: None,
832 }});"#
833 ).as_str();
834
835 continue;
836 }
837
838 json_field_names.push((
839 struct_field_name.clone(),
840 param_name.clone(),
841 field_type.clone(),
842 ));
843
844 define_struct_for_json += format!(
845 r#"
846 pub {struct_field_name}: {field_type},
847 "#
848 )
849 .as_str();
850
851 code += format!(r#"let property_of_type = {field_type}::to_swagger_definition(context);"#)
853 .as_str();
854
855 code += format!(
856 r#"let property_value = match property_of_type {{
857 rupring::swagger::macros::SwaggerDefinitionNode::Single(leaf) => {{
858 rupring::swagger::json::SwaggerProperty::Single(rupring::swagger::json::SwaggerSingleProperty {{
859 type_: leaf.type_,
860 description: "{description}".to_string(),
861 example: Some({example}.into()),
862 }})
863 }},
864 rupring::swagger::macros::SwaggerDefinitionNode::Array(array) => {{
865 rupring::swagger::json::SwaggerProperty::Array(rupring::swagger::json::SwaggerArrayProperty {{
866 type_: array.type_,
867 items: array.items,
868 description: "{description}".to_string(),
869 }})
870 }},
871 rupring::swagger::macros::SwaggerDefinitionNode::Object(object) => {{
872 let definition_name = {field_type}::get_definition_name();
873
874 context.definitions.insert(definition_name.clone(), object);
875
876 rupring::swagger::json::SwaggerProperty::Reference(rupring::swagger::json::SwaggerReferenceProperty {{
877 reference: "{SHARP}/definitions/".to_string() + definition_name.as_str(),
878 description: "{description}".to_string(),
879 }})
880 }},
881 }};"#
882 )
883 .as_str();
884
885 code += format!(
886 r#"swagger_definition.properties.insert("{field_name}".to_string(), property_value);"#
887 )
888 .as_str();
889 }
890
891 define_struct_for_json += format!(r#"}}"#).as_str();
892
893 code += "rupring::swagger::macros::SwaggerDefinitionNode::Object(swagger_definition)";
894
895 code += "}";
896
897 code += "}";
898
899 code += define_struct_for_json.as_str();
900
901 let mut request_bind_code = "".to_string();
902 request_bind_code +=
903 format!(r#"impl rupring::request::BindFromRequest for {struct_name} {{"#).as_str();
904
905 request_bind_code +=
906 "fn bind(request: rupring::request::Request) -> rupring::anyhow::Result<Self> {";
907 request_bind_code += "use rupring::request::ParamStringDeserializer;";
908 request_bind_code += "use rupring::request::QueryStringDeserializer;";
909
910 request_bind_code += format!("let mut json_bound = rupring::serde_json::from_str::<{struct_name}__JSON>(request.body.as_str())?;").as_str();
911
912 request_bind_code += format!("let bound = {struct_name} {{").as_str();
913
914 for (struct_field_name, _, _) in json_field_names {
915 request_bind_code +=
916 format!("{struct_field_name}: json_bound.{struct_field_name},").as_str();
917 }
918
919 for (struct_field_name, param_name, field_type) in path_field_names {
920 request_bind_code += format!(
921 r#"{struct_field_name}: {{
922 let param = rupring::request::ParamString(
923 request.path_parameters["{param_name}"].clone()
924 );
925
926 let deserialized: {field_type} = match param.deserialize() {{
927 Ok(v) => v,
928 Err(_) => return Err(rupring::anyhow::anyhow!("invalid parameter: {param_name}")),
929 }};
930
931 deserialized
932 }}
933 "#
934 )
935 .as_str();
936 }
937
938 for (struct_field_name, param_name, field_type) in query_field_names {
939 let mut code_if_field_type_is_none =
940 format!(r#"return Err(rupring::anyhow::anyhow!("invalid parameter: {param_name}"));"#);
941
942 if field_type.starts_with("Option<") || field_type.starts_with("Option::<") {
943 code_if_field_type_is_none = r#"
944 rupring::request::QueryString(vec![])
945 "#
946 .to_string();
947 }
948
949 request_bind_code += format!(
950 r#"{struct_field_name}: {{
951 let query = if let Some(query) = request.query_parameters.get("{param_name}") {{
952 rupring::request::QueryString(query.to_owned())
953 }} else {{
954 {code_if_field_type_is_none}
955 }};
956
957 let deserialized: {field_type} = match query.deserialize_query_string() {{
958 Ok(v) => v,
959 Err(_) => return Err(rupring::anyhow::anyhow!("invalid parameter: {param_name}")),
960 }};
961
962 deserialized
963 }},
964 "#
965 )
966 .as_str();
967 }
968
969 request_bind_code += format!("}};").as_str();
970
971 request_bind_code += "Ok(bound)";
972 request_bind_code += "}";
973
974 request_bind_code += format!(r#"}}"#).as_str();
975
976 code += request_bind_code.as_str();
977
978 return TokenStream::from_str(code.as_str()).unwrap();
979}