rustbasic_macro/
lib.rs

1//! # Rust Basic Macro
2//!
3//! `RustBasic` is a planned development that aims to make Rust easy to learn, teach, and use.
4
5// rustbasic macro - lib.rs
6// Thanks to `wusyong & Team` ( https://github.com/wusyong/smol-potat ) for the reference.
7// Thanks to `Fishrock123 & Team` ( https://github.com/async-rs/async-attributes ) for the reference.
8// Thanks to `all the creators` of the libraries used in this source code.
9// Thanks to `all RUST Team`.
10
11#![allow(unused_doc_comments)]
12#![allow(dead_code)]
13
14#![allow(unused_imports)]
15#![allow(unused_variables)]
16#![allow(unused_assignments)]
17
18use proc_macro::TokenStream;
19use proc_macro2::Span;
20use quote::{quote, quote_spanned};
21use syn::parse::{Parse, ParseStream};
22use syn::spanned::Spanned;
23use syn::Expr;
24use futures::executor::block_on;
25
26#[proc_macro_attribute]
27pub fn main(attr: TokenStream, item: TokenStream) -> TokenStream {
28    let input = syn::parse_macro_input!(item as syn::ItemFn);
29    let opts = syn::parse_macro_input!(attr as Opts);
30
31    let ret = &input.sig.output;
32    let inputs = &input.sig.inputs;
33    let name = &input.sig.ident;
34    let body = &input.block;
35    #[allow(unused_variables)]
36    let attrs = &input.attrs;
37    let vis = &input.vis;
38
39    let crate_root = opts.crate_root;
40
41    let threads = match opts.threads {
42        Some((num, span)) => {
43            let num = num.to_string();
44            Some(quote_spanned!(span=> #num))
45        }
46        #[cfg(feature = "auto")]
47        None => Some(quote! {
48            #crate_root::std::string::ToString::to_string(
49                &#crate_root::std::cmp::max(#crate_root::num_cpus::get(), 1)
50            )
51        }),
52        #[cfg(not(feature = "auto"))]
53        None => None,
54    };
55
56    #[allow(unused_variables)]
57    let set_threads = threads.map(|threads| {
58        quote! {
59            #crate_root::std::env::set_var(
60                "RUSTBASIC-THREADS",
61                #threads,
62            );
63        }
64    });
65
66    let mut result : proc_macro2::TokenStream = proc_macro2::TokenStream::new();
67
68    match input.sig.asyncness {
69        None | Some(_) if input.sig.ident != "main" => {    // => If it is `not async` or `not main()`
70            result = quote! {
71                #vis fn #name(#inputs) #ret {
72                    #body
73                }
74            }
75        }
76        _ => {                                              //  => If it is `async main()`
77            result = quote! {
78                #vis fn main() #ret {
79                    futures::executor::block_on( async { async_main().await } );
80                }
81                async fn async_main() #ret {
82                    #body
83                }
84            }
85        }
86    }
87
88    result.into()
89}
90
91#[proc_macro_attribute]
92pub fn print(attr: TokenStream, item: TokenStream) -> TokenStream {
93
94    println!("attr: {:?}", attr.clone());
95    println!("item: {:?}", item.clone());
96
97    let input = syn::parse_macro_input!(item as syn::ItemFn);
98    let opts = syn::parse_macro_input!(attr as Opts);
99
100//    println!("input: {}", input);
101//    println!("opts: {}", opts);
102
103    let ret = &input.sig.output;
104    let inputs = &input.sig.inputs;
105    let name = &input.sig.ident;
106    let body = &input.block;
107    #[allow(unused_variables)]
108    let attrs = &input.attrs;
109    let vis = &input.vis;
110
111    let crate_root = opts.crate_root;
112
113    let threads = match opts.threads {
114        Some((num, span)) => {
115            let num = num.to_string();
116            Some(quote_spanned!(span=> #num))
117        }
118        #[cfg(feature = "auto")]
119        None => Some(quote! {
120            #crate_root::std::string::ToString::to_string(
121                &#crate_root::std::cmp::max(#crate_root::num_cpus::get(), 1)
122            )
123        }),
124        #[cfg(not(feature = "auto"))]
125        None => None,
126    };
127
128    #[allow(unused_variables)]
129    let set_threads = threads.map(|threads| {
130        quote! {
131            #crate_root::std::env::set_var(
132                "RUSTBASIC-THREADS",
133                #threads,
134            );
135        }
136    });
137
138    let result : proc_macro2::TokenStream = proc_macro2::TokenStream::new();
139/*
140    match input.sig.asyncness {
141        None | Some(_) if input.sig.ident != "main" => {    // => If it is `not async` or `not main()`
142            result = quote! {
143                #[allow(unused_imports)]
144                #[allow(unused_attributes)]
145                #[allow(dead_code)]
146                #[allow(unused_variables)]
147                #vis fn #name(#inputs) #ret {
148                    #body
149                }
150            }
151        }
152        _ => {                                              //  => If it is `async main()`
153            result = quote! {
154                #vis fn main() #ret {
155                    futures::executor::block_on( async { async_main().await } );
156                }
157                #[allow(unused_imports)]
158                #[allow(unused_attributes)]
159                #[allow(dead_code)]
160                #[allow(unused_variables)]
161                async fn async_main() #ret {
162                    #body
163                }
164            }
165        }
166    }
167*/
168    result.into()
169}
170
171#[proc_macro_attribute]
172pub fn start(attr: TokenStream, item: TokenStream) -> TokenStream {
173    let input = syn::parse_macro_input!(item as syn::ItemFn);
174    let opts = syn::parse_macro_input!(attr as Opts);
175
176    let ret = &input.sig.output;
177    let inputs = &input.sig.inputs;
178    let name = &input.sig.ident;
179    let body = &input.block;
180    #[allow(unused_variables)]
181    let attrs = &input.attrs;
182    let vis = &input.vis;
183
184    let crate_root = opts.crate_root;
185
186    let threads = match opts.threads {
187        Some((num, span)) => {
188            let num = num.to_string();
189            Some(quote_spanned!(span=> #num))
190        }
191        #[cfg(feature = "auto")]
192        None => Some(quote! {
193            #crate_root::std::string::ToString::to_string(
194                &#crate_root::std::cmp::max(#crate_root::num_cpus::get(), 1)
195            )
196        }),
197        #[cfg(not(feature = "auto"))]
198        None => None,
199    };
200
201    #[allow(unused_variables)]
202    let set_threads = threads.map(|threads| {
203        quote! {
204            #crate_root::std::env::set_var(
205                "RUSTBASIC-THREADS",
206                #threads,
207            );
208        }
209    });
210
211    let mut result : proc_macro2::TokenStream = proc_macro2::TokenStream::new();
212
213    match input.sig.asyncness {
214        None | Some(_) if input.sig.ident != "main" => {    // => If it is `not async` or `not main()`
215            result = quote! {
216                #[allow(unused_imports)]
217                #[allow(unused_attributes)]
218                #[allow(dead_code)]
219                #[allow(unused_variables)]
220                #[allow(unused_assignments)]
221                #[allow(unused_doc_comments)]
222                #vis fn #name(#inputs) #ret {
223                    #body
224                }
225            }
226        }
227        _ => {                                              //  => If it is `async main()`
228            result = quote! {
229                #vis fn main() #ret {
230                    futures::executor::block_on( async { async_main().await } );
231                }
232                #[allow(unused_imports)]
233                #[allow(unused_attributes)]
234                #[allow(dead_code)]
235                #[allow(unused_variables)]
236                #[allow(unused_assignments)]
237                #[allow(unused_doc_comments)]
238                async fn async_main() #ret {
239                    #body
240                }
241            }
242        }
243    }
244
245    result.into()
246}
247
248#[proc_macro_attribute]
249pub fn func(attr: TokenStream, item: TokenStream) -> TokenStream {
250    let input = syn::parse_macro_input!(item as syn::ItemFn);
251    let opts = syn::parse_macro_input!(attr as Opts);
252
253    let ret = &input.sig.output;
254    let inputs = &input.sig.inputs;
255    let name = &input.sig.ident;
256    let body = &input.block;
257    #[allow(unused_variables)]
258    let attrs = &input.attrs;
259    let vis = &input.vis;
260
261    let crate_root = opts.crate_root;
262
263    let threads = match opts.threads {
264        Some((num, span)) => {
265            let num = num.to_string();
266            Some(quote_spanned!(span=> #num))
267        }
268        #[cfg(feature = "auto")]
269        None => Some(quote! {
270            #crate_root::std::string::ToString::to_string(
271                &#crate_root::std::cmp::max(#crate_root::num_cpus::get(), 1)
272            )
273        }),
274        #[cfg(not(feature = "auto"))]
275        None => None,
276    };
277
278    #[allow(unused_variables)]
279    let set_threads = threads.map(|threads| {
280        quote! {
281            #crate_root::std::env::set_var(
282                "RUSTBASIC-THREADS",
283                #threads,
284            );
285        }
286    });
287
288    let mut result : proc_macro2::TokenStream = proc_macro2::TokenStream::new();
289
290    match input.sig.asyncness {
291        None => {                                           // => If it is `not async`
292            result = quote! {
293                #[allow(unused_imports)]
294                #[allow(unused_attributes)]
295                #[allow(dead_code)]
296                #[allow(unused_variables)]
297                #[allow(unused_assignments)]
298                #[allow(unused_doc_comments)]
299                #vis fn #name(#inputs) #ret {
300                    #body
301                }
302            }
303        },
304        Some(_) if input.sig.ident != "main" => {           //  => If it is `async func()`
305            result = quote! {
306                #[allow(unused_imports)]
307                #[allow(unused_attributes)]
308                #[allow(dead_code)]
309                #[allow(unused_variables)]
310                #[allow(unused_assignments)]
311                #[allow(unused_doc_comments)]
312                #vis fn rustbasic_asyncfunc() #ret {
313                    async fn #name(#inputs) {
314                        #body
315                    }
316                futures::executor::block_on( async { 
317                        #name().await;
318                    } );
319                }
320            }
321        },
322        _ => {                                              //  => If it is `async main()`
323            result = quote! {
324                #vis fn main() #ret {
325                    futures::executor::block_on( async { async_main().await } );
326                }
327                #[allow(unused_imports)]
328                #[allow(unused_attributes)]
329                #[allow(dead_code)]
330                #[allow(unused_variables)]
331                #[allow(unused_doc_comments)]
332                async fn async_main() #ret {
333                    #body
334                }
335            }
336        }
337    }
338
339    result.into()
340}
341
342#[proc_macro_attribute]
343pub fn function(attr: TokenStream, item: TokenStream) -> TokenStream {
344    let input = syn::parse_macro_input!(item as syn::ItemFn);
345    let opts = syn::parse_macro_input!(attr as Opts);
346
347    let ret = &input.sig.output;
348    let inputs = &input.sig.inputs;
349    let name = &input.sig.ident;
350    let body = &input.block;
351    #[allow(unused_variables)]
352    let attrs = &input.attrs;
353    let vis = &input.vis;
354
355    let crate_root = opts.crate_root;
356
357    let threads = match opts.threads {
358        Some((num, span)) => {
359            let num = num.to_string();
360            Some(quote_spanned!(span=> #num))
361        }
362        #[cfg(feature = "auto")]
363        None => Some(quote! {
364            #crate_root::std::string::ToString::to_string(
365                &#crate_root::std::cmp::max(#crate_root::num_cpus::get(), 1)
366            )
367        }),
368        #[cfg(not(feature = "auto"))]
369        None => None,
370    };
371
372    #[allow(unused_variables)]
373    let set_threads = threads.map(|threads| {
374        quote! {
375            #crate_root::std::env::set_var(
376                "RUSTBASIC-THREADS",
377                #threads,
378            );
379        }
380    });
381
382    let result : proc_macro2::TokenStream;
383
384    match input.sig.asyncness {
385        None | Some(_) if input.sig.ident != "main" => {    // => If it is `not async` or `not main()`
386            result = quote! {
387                #[allow(unused_imports)]
388                #[allow(unused_attributes)]
389                #[allow(dead_code)]
390                #[allow(unused_variables)]
391                #[allow(unused_doc_comments)]
392                #vis fn #name(#inputs) #ret {
393                    #body
394                }
395            }
396        }
397        _ => {                                              //  => If it is `async main()`
398            result = quote! {
399                #vis fn main() #ret {
400                    futures::executor::block_on( async { async_main().await } );
401                }
402                #[allow(unused_imports)]
403                #[allow(unused_attributes)]
404                #[allow(dead_code)]
405                #[allow(unused_variables)]
406                #[allow(unused_doc_comments)]
407                async fn async_main() #ret {
408                    #body
409                }
410            }
411        }
412    }
413
414    result.into()
415}
416
417struct Opts {
418    crate_root: syn::Path,
419    threads: Option<(u32, Span)>,
420}
421
422impl Parse for Opts {
423    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
424        let mut crate_root = None;
425        let mut threads = None;
426
427        loop {
428            if input.is_empty() {
429                break;
430            }
431
432            let name_value: syn::MetaNameValue = input.parse()?;
433            let ident = match name_value.path.get_ident() {
434                Some(ident) => ident,
435                None => {
436                    return Err(syn::Error::new_spanned(
437                        name_value.path,
438                        "Must be a single ident",
439                    ))
440                }
441            };
442            match &*ident.to_string().to_lowercase() {
443                "threads" => match &name_value.lit {
444                    syn::Lit::Int(expr) => {
445                        if threads.is_some() {
446                            return Err(syn::Error::new_spanned(
447                                name_value,
448                                "multiple threads argments",
449                            ));
450                        }
451
452                        let num = expr.base10_parse::<std::num::NonZeroU32>()?;
453                        threads = Some((num.get(), expr.span()));
454                    }
455                    _ => {
456                        return Err(syn::Error::new_spanned(
457                            name_value,
458                            "threads argument must be an integer",
459                        ))
460                    }
461                },
462                "crate" => match &name_value.lit {
463                    syn::Lit::Str(path) => {
464                        if crate_root.is_some() {
465                            return Err(syn::Error::new_spanned(
466                                name_value,
467                                "multiple crate arguments",
468                            ));
469                        }
470
471                        crate_root = Some(path.parse()?);
472                    }
473                    _ => {
474                        return Err(syn::Error::new_spanned(
475                            name_value,
476                            "crate argument must be a string",
477                        ))
478                    }
479                },
480                name => {
481                    return Err(syn::Error::new_spanned(
482                        name,
483                        "unknown attribute {}, expected `threads` or `crate`",
484                    ));
485                }
486            }
487
488            input.parse::<Option<syn::Token![,]>>()?;
489        }
490
491        Ok(Self {
492            crate_root: crate_root.unwrap_or_else(|| syn::parse2(quote!(::rustbasic)).unwrap()),
493            threads,
494        })
495    }
496}
497
498async fn rustbasic_macro_addlib_temp() {
499}
500
501fn rustbasic_macro_addlib() {
502    futures::executor::block_on( rustbasic_macro_addlib_temp() );
503}