1use darling::FromMeta;
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::{
5 parse_macro_input, punctuated::Punctuated, token::Paren, AttributeArgs, FnArg, Item, ItemFn,
6 Pat, ReturnType, Type, TypeTuple,
7};
8
9#[derive(Debug, FromMeta)]
10struct MainMacroArgs {
11 #[darling(default)]
13 tokio: Option<String>,
14}
15
16#[derive(Debug, FromMeta)]
17struct NodeMacroArgs {
18 #[darling(default)]
20 async_trait: Option<String>,
21}
22
23#[proc_macro_attribute]
25pub fn main(
26 args: proc_macro::TokenStream,
27 input: proc_macro::TokenStream,
28) -> proc_macro::TokenStream {
29 let attr_args = parse_macro_input!(args as AttributeArgs);
30 let function = parse_macro_input!(input as ItemFn);
31
32 let args = match MainMacroArgs::from_list(&attr_args) {
33 Ok(v) => v,
34 Err(e) => {
35 return proc_macro::TokenStream::from(e.write_errors());
36 }
37 };
38
39 let tokio: TokenStream = args
40 .tokio
41 .as_deref()
42 .unwrap_or("mekena_tokio")
43 .parse()
44 .unwrap();
45 let tokio_stringified: String = tokio.to_string().split_whitespace().collect();
46
47 let _asyncness = function
48 .sig
49 .asyncness
50 .expect("Could not find `async` marker.");
51
52 let function_output = if let ReturnType::Type(_, t) = function.sig.output {
53 *t
54 } else {
55 Type::Tuple(TypeTuple {
56 paren_token: Paren::default(),
57 elems: Punctuated::new(),
58 })
59 };
60
61 let system_name = {
62 if let Some(first) = function.sig.inputs.first() {
63 if let FnArg::Typed(pattern_type) = first {
64 if let Pat::Ident(identifier) = &*pattern_type.pat {
65 &identifier.ident
66 } else {
67 panic!("could not find system variable name")
68 }
69 } else {
70 panic!("could not find system variable pattern")
71 }
72 } else {
73 panic!("could not find system variable in fn sig");
74 }
75 };
76
77 let function_contents = function.block;
78
79 quote! {
80 use mekena::re::tokio as mekena_tokio;
83
84 #[#tokio::main(crate = #tokio_stringified)]
85 async fn main() -> #function_output {
86 let mut #system_name = mekena::system::System::new();
87 #function_contents
88 }
89 }
90 .into()
91}
92
93#[proc_macro_attribute]
96pub fn node(
97 args: proc_macro::TokenStream,
98 input: proc_macro::TokenStream,
99) -> proc_macro::TokenStream {
100 let attr_args = parse_macro_input!(args as AttributeArgs);
101 let item = parse_macro_input!(input as Item);
102
103 let args = match NodeMacroArgs::from_list(&attr_args) {
104 Ok(v) => v,
105 Err(e) => {
106 return proc_macro::TokenStream::from(e.write_errors());
107 }
108 };
109
110 let async_trait: TokenStream = args
111 .async_trait
112 .as_deref()
113 .unwrap_or("mekena::re::async_trait")
114 .parse()
115 .unwrap();
116
117 quote! {
118 #[#async_trait::async_trait(?Send)]
119 #item
120 }
121 .into()
122}