1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use syn::{File as SynFile, Item, Type};
#[derive(Debug)]
pub enum TypeClass {
InputBody,
QueryParam,
Path,
Return,
Invalid
}
#[derive(Debug, Clone)]
pub enum HandlerRequestType {
Get,
Post,
Delete,
Put
}
#[derive(Debug)]
pub struct HandlerType {
pub type_value: Type,
pub class: Option<TypeClass>,
pub handler_type: HandlerRequestType
}
pub fn extract_handler_types(route_source: &str) -> Option<Vec<Option<HandlerType>>> {
let parsed_file: SynFile = syn::parse_str(route_source).unwrap();
for item in parsed_file.items {
if let Item::Fn(function) = item {
if is_valid_handler("rapid_handler", function.attrs) {
let mut function_types: Vec<Option<HandlerType>> = Vec::new();
let arg_types = function.sig.inputs.iter();
let function_name = function.sig.ident;
for type_value in arg_types {
if let syn::FnArg::Typed(typed) = type_value {
let rust_type = *typed.ty.clone();
let type_class = get_type_class(rust_type.clone());
function_types.push(Some(HandlerType {
type_value: rust_type,
class: type_class,
handler_type: match function_name.to_string().as_str() {
"get" => HandlerRequestType::Get,
"post" => HandlerRequestType::Post,
"delete" => HandlerRequestType::Delete,
"put" => HandlerRequestType::Put,
_ => HandlerRequestType::Get
}
}));
}
}
return Some(function_types);
}
}
}
None
}
pub fn get_type_class(rust_type: Type) -> Option<TypeClass> {
match rust_type {
Type::Reference(path) => get_type_class(*path.elem),
Type::Path(path) => {
let segment = path.path.segments.last().unwrap();
let tokens = &segment.ident;
Some(match tokens.to_string().as_str() {
"Path" => TypeClass::Path,
"Query" => TypeClass::QueryParam,
"Json" => TypeClass::InputBody, _ => TypeClass::Invalid
}
)
},
_ => None
}
}
pub fn is_valid_handler(macro_name: &str, attributes: Vec<syn::Attribute> ) -> bool {
attributes.iter().any(|attr| {
attr.path()
.segments
.iter()
.any(|segment| segment.ident == macro_name)
})
}
pub fn space() -> String {
let mut space_string = "".to_string();
for _ in 0..2 {
space_string.push(' ');
}
space_string
}