1use proc_macro::TokenStream;
5use proc_macro2::{Ident, Span as Span2, TokenStream as TokenStream2, TokenTree as TokenTree2};
6use quote::quote;
7
8mod json;
9
10#[proc_macro_attribute]
11pub fn json_request(attr: TokenStream, item: TokenStream) -> TokenStream {
12 json::json_request(attr, item)
13}
14
15#[proc_macro]
16pub fn m(items: TokenStream) -> TokenStream {
17 let items = proc_macro2::TokenStream::from(items);
18
19 let idents = items
20 .into_iter()
21 .filter(|v| matches!(v, TokenTree2::Ident(_)))
22 .clone();
23 let pointers = idents.clone().into_iter().map(|_| {
24 quote! {
25 MiddlewareFnPointer<_>
26 }
27 });
28
29 let gen = quote! {
30 {
31 use thruster::parser::middleware_traits::{MiddlewareFnPointer, MiddlewareTuple, ToTuple};
32
33 let val: (#( #pointers),*,) = (#( #idents ),*,);
34 val.to_tuple()
35 }
36 };
37
38 gen.into()
44}
45
46#[deprecated(note = "Will be removed in future versions in favor of the simpler m macro")]
47#[proc_macro]
48pub fn async_middleware(items: TokenStream) -> TokenStream {
49 let items = proc_macro2::TokenStream::from(items);
50
51 let mut item_iter = items.into_iter();
52
53 item_iter.next();
54 item_iter.next();
55
56 let items = match item_iter.next() {
57 Some(TokenTree2::Group(g)) => g.stream(),
58 _ => panic!("Second item should be a group."),
59 };
60
61 let idents = items
62 .into_iter()
63 .filter(|v| matches!(v, TokenTree2::Ident(_)))
64 .clone();
65 let pointers = idents.clone().into_iter().map(|_| {
66 quote! {
67 MiddlewareFnPointer<_>
68 }
69 });
70
71 let gen = quote! {
72 {
73 use thruster::parser::middleware_traits::{MiddlewareFnPointer, MiddlewareTuple, ToTuple};
74
75 let val: (#( #pointers),*,) = (#( #idents ),*,);
76 val.to_tuple()
77 }
78 };
79
80 gen.into()
86}
87
88#[proc_macro_attribute]
89pub fn middleware(attr: TokenStream, item: TokenStream) -> TokenStream {
90 middleware_fn(attr, item)
91}
92
93#[proc_macro_attribute]
94pub fn middleware_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
95 if let syn::Item::Fn(mut function_item) = syn::parse(item.clone()).unwrap() {
96 let name = function_item.sig.ident.clone();
97 let new_name = Ident::new(&format!("__async_{}", name), Span2::call_site());
98 function_item.sig.ident = new_name.clone();
99
100 let visibility = function_item.vis.clone();
101 let arguments = function_item.sig.inputs.clone();
102 let generics = function_item.sig.generics.clone();
103
104 let context_type = match &arguments[0] {
105 syn::FnArg::Typed(cap) => &cap.ty,
106 _ => panic!("Expected the first argument to be a context type"),
107 };
108 let new_return_type = Ident::new(
109 &format!("__MiddlewareReturnValue_{}", name),
110 Span2::call_site(),
111 );
112 let new_rbf_type = Ident::new(&format!("__ReusableBoxFuture_{}", name), Span2::call_site());
113 let crate_path = match attr.to_string().as_str() {
114 "_internal" => quote! {
115 crate::{core::{ MiddlewareReturnValue as #new_return_type }, ReusableBoxFuture as #new_rbf_type }
116 },
117 _ => quote! {
118 thruster::{ MiddlewareReturnValue as #new_return_type, ReusableBoxFuture as #new_rbf_type }
119 },
120 };
121
122 let gen = quote! {
123 #function_item
124
125 use #crate_path;
126 #visibility fn #name#generics(ctx: #context_type, next: MiddlewareNext<#context_type>) -> #new_return_type<#context_type> {
127 #new_rbf_type::new(#new_name(ctx, next))
128 }
129 };
130
131 gen.into()
137 } else {
138 item
139 }
140}
141
142#[proc_macro_attribute]
143pub fn context_state(_attr: TokenStream, item: TokenStream) -> TokenStream {
144 let item = proc_macro2::TokenStream::from(item);
145 let mut items = item.clone().into_iter();
146
147 loop {
148 if let Some(TokenTree2::Ident(i)) = items.next() {
149 if &i.to_string() == "struct" {
150 break;
151 }
152 } else {
153 panic!("First token must be an identifier, like `State` or `Config`.");
154 }
155 }
156
157 let name = if let Some(TokenTree2::Ident(i)) = items.next() {
158 i
159 } else {
160 panic!("First token must be an identifier, like `State` or `Config`.");
161 };
162
163 let mut groups = vec![];
164 let mut current_group = vec![];
165
166 if let Some(TokenTree2::Group(items)) = items.next() {
167 for token in items.stream().into_iter() {
168 if let TokenTree2::Punct(p) = &token {
169 if p.as_char() == ',' {
170 groups.push(current_group);
171 current_group = vec![];
172 } else {
173 current_group.push(token);
174 }
175 } else {
176 current_group.push(token);
177 }
178 }
179 } else {
180 panic!("Third argument must be a group in the form of [], (), or braces.");
181 }
182
183 if !current_group.is_empty() {
184 groups.push(current_group);
185 }
186
187 let groups = groups
188 .into_iter()
189 .map(|v| {
190 let mut stream = TokenStream2::new();
191 stream.extend(v);
192 stream
193 })
194 .collect::<Vec<TokenStream2>>();
195
196 let mut impls = vec![];
197
198 let mut i = 0;
199 for group in groups.iter() {
200 let i_token = proc_macro2::Literal::usize_unsuffixed(i);
201 impls.push(quote! {
202 impl ContextState<#group> for #name {
203 fn get(&self) -> &#group {
204 &self.#i_token
205 }
206
207 fn get_mut(&mut self) -> &mut #group {
208 &mut self.#i_token
209 }
210 }
211 });
212 i += 1;
213 }
214
215 let gen = quote! {
216 #item
217
218 use thruster::ContextState;
219
220 #(
221 #impls
222 )*
223 };
224
225 gen.into()
226}
227
228#[proc_macro]
229pub fn generate_tuples(items: TokenStream) -> TokenStream {
230 let items = proc_macro2::TokenStream::from(items);
231
232 let mut idents: Vec<Ident> = items
233 .into_iter()
234 .filter(|v| matches!(v, TokenTree2::Ident(_)))
235 .map(|v| {
236 if let TokenTree2::Ident(i) = v {
237 i
238 } else {
239 panic!("Should never get here.")
240 }
241 })
242 .collect();
243 let ident_count = idents.len();
244
245 let mut vec_collection: Vec<Vec<Ident>> = vec![];
246 let mut aggregator = vec![];
247
248 while !idents.is_empty() {
249 aggregator.push(idents.remove(0));
250
251 vec_collection.push(aggregator.clone());
252 }
253
254 let mut enum_variants = vec![];
255 let mut to_tuple_variants = vec![];
256 let mut from_tuple_variants = vec![];
257 for i in 0..vec_collection.len() {
258 let idents = vec_collection.get(i).unwrap();
259 let last_a = idents.last().unwrap();
260 let last_b = idents.last().unwrap();
261 let last_d = idents.last().unwrap();
262
263 let values_a: Vec<TokenStream2> = idents
264 .iter()
265 .map(|_v| {
266 quote! {
267 M<T>
268 }
269 })
270 .collect();
271 let values_b: Vec<Ident> = idents
272 .iter()
273 .map(|v| Ident::new(&format!("{}", v).to_lowercase(), Span2::call_site()))
274 .collect();
275 let values_c = values_b.clone();
276 let values_e = values_a.clone();
277 let values_f = values_b.clone();
278 let values_g = values_b.clone();
279
280 enum_variants.push(quote! {
281 #last_a(#(#values_a),*)
282 });
283
284 to_tuple_variants.push(quote! {
285 MiddlewareTuple::#last_b(#(#values_b),*) => (#(#values_c),*,)
286 });
287
288 from_tuple_variants.push(quote! {
289 #[allow(unused_parens)]
290 impl<T: 'static + Send> ToTuple<T> for (#(#values_e),*,) {
291 fn to_tuple(self) -> MiddlewareTuple<T> {
292 #[allow(non_snake_case)]
293 let (#(#values_f),*,) = self;
294
295 MiddlewareTuple::#last_d(#(#values_g),*)
296 }
297 }
298 });
299 }
300
301 const VALUES: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
302 let mut combine_outter = vec![];
303 for i in 0..vec_collection.len() {
304 let idents = vec_collection.get(i).unwrap();
305 let last = idents.last().unwrap();
306
307 let values_a: Vec<Ident> = idents
308 .iter()
309 .map(|v| Ident::new(&format!("{}", v).to_lowercase(), Span2::call_site()))
310 .collect();
311
312 let mut inner_values = vec![];
313 for j in 0..vec_collection.len() {
314 let inner_idents = vec_collection.get(j).unwrap();
315
316 let outter = Ident::new(&format!("{}", last).to_lowercase(), Span2::call_site());
317 let last = inner_idents.last().unwrap();
318
319 let values: Vec<Ident> = inner_idents
320 .iter()
321 .map(|v| {
322 Ident::new(
323 &format!("{}_{}", outter, v).to_lowercase(),
324 Span2::call_site(),
325 )
326 })
327 .collect();
328
329 let count_usize = i + j + 2;
330 let count = proc_macro2::Literal::usize_suffixed(count_usize);
331 if count_usize <= ident_count {
332 let output_variant = Ident::new(
333 &format!("{}", VALUES.chars().nth(count_usize - 1).unwrap()),
334 Span2::call_site(),
335 );
336 let values_c = values_a.clone();
337 let values_d = values.clone();
338 let values_e = values.clone();
339
340 inner_values.push(quote! {
341 MiddlewareTuple::#last(#(#values_d),*) => MiddlewareTuple::#output_variant(#(#values_c),*, #(#values_e),*)
342 });
343 } else {
344 inner_values.push(quote! {
345 MiddlewareTuple::#last(#(#values),*) => panic!("Can't handle {}-tuple", #count)
346 });
347 }
348 }
349
350 combine_outter.push(quote! {
351 MiddlewareTuple::#last(#(#values_a),*) => {
352 match other {
353 #(#inner_values),*
354 }
355 }
356 });
357 }
358
359 let gen = quote! {
360 #[derive(Clone, Debug)]
361 pub enum MiddlewareTuple<T> {
362 #(
363 #enum_variants
364 ),*
365 }
366
367 pub trait ToTuple<T> {
368 fn to_tuple(self) -> MiddlewareTuple<T>;
369 }
370
371 impl<T: Send> MiddlewareTuple<T> {
372 pub fn combine(self, other: MiddlewareTuple<T>) -> MiddlewareTuple<T> {
373 match self {
374 #(
375 #combine_outter
376 ),*
377 }
378 }
379 }
380
381 impl<T: 'static + Send> IntoMiddleware<T, M<T>> for MiddlewareTuple<T> {
382 fn middleware(self) -> Box<dyn Fn(T) -> ReusableBoxFuture<Result<T, ThrusterError<T>>> + Send + Sync> {
383 match self {
384 #(
385 #to_tuple_variants.middleware()
386 ),*
387 }
388 }
389 }
390
391
392 #(#from_tuple_variants)*
393 };
394
395 gen.into()
401}