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
#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;
extern crate proc_macro;
mod openapi_attr;
mod routes_with_openapi;
use proc_macro::TokenStream;
use syn::{token::Paren, Ident, GenericArgument, Type, TypeNever, TypeParen};
use syn::visit_mut::{self, VisitMut};
#[proc_macro_attribute]
pub fn openapi(args: TokenStream, mut input: TokenStream) -> TokenStream {
input = preserve_span_information(input);
input.extend(openapi_attr::parse(args, input.clone()));
input
}
#[proc_macro]
pub fn routes_with_openapi(input: TokenStream) -> TokenStream {
routes_with_openapi::parse(input)
}
fn preserve_span_information(input: TokenStream) -> TokenStream {
let mut parsed_input: syn::Item = syn::parse(input).unwrap();
GenericTypeVisitor.visit_item_mut(&mut parsed_input);
quote!(#parsed_input).into()
}
struct GenericTypeVisitor;
impl VisitMut for GenericTypeVisitor {
fn visit_generic_argument_mut(&mut self, node: &mut GenericArgument) {
visit_mut::visit_generic_argument_mut(self, node);
if let GenericArgument::Type(ref mut ty) = node {
let ty_owned = std::mem::replace(ty, dummy_type());
*ty = Type::Paren(TypeParen {
paren_token: Paren::default(),
elem: Box::new(ty_owned),
})
}
}
}
fn dummy_type() -> Type {
Type::Never(TypeNever {
bang_token: Default::default(),
})
}
fn get_add_operation_fn_name(route_fn_name: &Ident) -> Ident {
Ident::new(
&format!("okapi_add_operation_for_{}_", route_fn_name),
route_fn_name.span(),
)
}