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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{parse_quote, spanned::Spanned, Error, FnArg, Ident, ItemFn, Type};
pub fn impl_macro_find_singleton(_attr: TokenStream, item: ItemFn) -> TokenStream {
generate(item).unwrap_or_else(|e| e.to_compile_error().into())
}
fn generate(mut item: ItemFn) -> Result<TokenStream, Error> {
let vis = &item.vis;
if let None = item.sig.asyncness {
return Err(Error::new(
item.sig.fn_token.span(),
"The function must be declared as async",
));
};
let inputs = &item.sig.inputs;
if inputs.iter().any(|val| match val {
FnArg::Receiver(_) => true,
_ => false,
}) {
return Err(Error::new(
inputs.span(),
"The function must not have a receiver, self",
));
}
let mut streams = Vec::new();
for (index, fn_arg) in item.sig.inputs.iter_mut().enumerate() {
match fn_arg {
FnArg::Receiver(_) => {}
FnArg::Typed(pat_type) => {
// println!("pate: {:#?}", pat_type);
match pat_type.ty.as_mut() {
syn::Type::Path(type_path) => {
let is_single = type_path.path.segments.iter().any(|seg| seg.ident.to_string().contains("FindSingleton"));
for seg in type_path.path.segments.iter_mut() {
if seg.ident.to_string().contains("FindSingleton")
&& match &seg.arguments {
syn::PathArguments::AngleBracketed(_) => true,
_ => false,
}
{
match &mut seg.arguments {
syn::PathArguments::AngleBracketed(angle_bracketed) => {
let mut flag = false;
if let Some(syn::GenericArgument::Type(typ)) =
angle_bracketed.args.first()
{
if let Type::Path(type_path) = typ {
let original_variable = match pat_type.pat.as_ref() {
syn::Pat::Ident(pat_ident) => {
pat_ident.ident.clone()
}
syn::Pat::TupleStruct(pat_tuple_struct) => {
if let Some(syn::Pat::Ident(pat_ident)) =
pat_tuple_struct.elems.first()
{
pat_ident.ident.clone()
} else {
return Err(Error::new(
pat_type.pat.span(),
"The pattern must be an identifier or a tuple struct with one identifier"));
}
}
_ => return Err(Error::new(
pat_type.pat.span(),
"The pattern must be an identifier or a tuple struct with one identifier",
))
};
let arg = Type::Path(type_path.clone());
let variable = Ident::new(& format!("_my_state{}", index), Span::call_site());
let single_name = Ident::new(&crate::util::single::field_name_to_singleton_name(&original_variable.to_string()), Span::call_site());
let stream = quote! {
let #original_variable = #variable.get_single_with_name::<#arg>(stringify!(#single_name)).await;
};
streams.push(stream);
flag = true;
}
}
if flag {
angle_bracketed.args.clear();
angle_bracketed.args.push(syn::GenericArgument::Type(
parse_quote!(::next_web_core::state::application_state::ApplicationState)
));
let pat = syn::Pat::Ident(
syn::PatIdent { attrs: vec![], by_ref: None, mutability: None, ident:
Ident::new(format!("_my_state{}", index).as_str(), Span::call_site()), subpat: None
}
);
pat_type.pat = Box::new(pat);
}
}
_ => {}
}
}
}
if is_single {
let arg: syn::Type = parse_quote!(::next_web_core::state::application_state::ApplicationState);
let path: syn::Path = parse_quote!(::axum::Extension<#arg>);
type_path.path = path;
}
}
_ => {}
};
}
}
}
let sig = &item.sig;
let block = &item.block.stmts;
let token_stream = quote! {
#vis #sig
{
#(#streams)*
#(#block)*
}
};
// println!("token_stream: \n{}", token_stream.to_string());
Ok(token_stream.into())
}