rusnap_macros/
lib.rs

1use proc_macro::{Span, TokenStream};
2use quote::quote;
3use syn::{parse_macro_input, token::Pub, FnArg, Ident, ItemFn, Visibility};
4
5/// Create a endpoint from an async function
6#[proc_macro_attribute]
7pub fn handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
8    let mut input = parse_macro_input!(item as ItemFn);
9
10    let struct_name = input.sig.ident.clone();
11
12    let mod_name = Ident::new(
13        &format!("__rusnap_{}", &input.sig.ident),
14        Span::call_site().into(),
15    );
16
17    input.sig.ident = mod_name.clone();
18
19    let mut arg_name = Vec::with_capacity(input.sig.inputs.len());
20
21    for (index, arg) in input.sig.inputs.iter().enumerate() {
22        if let FnArg::Typed(_) = arg {
23            let name = Ident::new(&format!("_rh_a{}", index), Span::call_site().into());
24            arg_name.push(name);
25        }
26    }
27
28    let expanded = quote! {
29
30        mod #mod_name {
31            use super::*;
32            use rusnap::{
33                wasm_bindgen::JsValue, exports::{types::{FromRequest, IntoResponse}, Endpoint}, utils::JsResult,
34            };
35
36            #input
37
38            #[allow(non_camel_case_types)]
39            pub struct #struct_name;
40
41            #[rusnap::async_trait(?Send)]
42            impl Endpoint for #struct_name {
43                async fn handle(
44                    &self,
45                    method: &str,
46                    params: JsValue,
47                    data: &dyn std::any::Any,
48                    _origin: Option<&str>,
49                ) -> JsResult<JsValue> {
50
51                    #(
52                        let #arg_name = FromRequest::from_request(method, params.clone(), data).await;
53                    )*
54
55                    let r = #mod_name( #(#arg_name),* ).await;
56
57                    Ok(r.into_response().await?)
58                }
59            }
60        }
61
62        pub use #mod_name::#struct_name;
63
64    };
65
66    TokenStream::from(expanded)
67}
68
69/// Main function
70#[proc_macro_attribute]
71pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream {
72    let mut input = parse_macro_input!(item as ItemFn);
73
74    input.vis = Visibility::Public(Pub::default());
75
76    let expanded = quote! {
77        mod __rusnp_entry {
78            use rusnap::{wasm_bindgen::{self, JsValue}, wasm_bindgen_futures, exports, utils::JsResult};
79
80            use super::*;
81
82            #[wasm_bindgen::prelude::wasm_bindgen(js_name = _entry)]
83            #input
84
85            #[wasm_bindgen::prelude::wasm_bindgen]
86            pub async fn on_rpc_request(
87                origin: &str,
88                method: &str,
89                req: JsValue
90            ) -> JsResult<JsValue> {
91                exports::on_rpc_request(origin, method, req).await
92            }
93
94            #[wasm_bindgen::prelude::wasm_bindgen]
95            pub async fn on_transaction(
96                transaction: JsValue,
97                chainid: u64,
98                req: JsValue
99            ) -> JsResult<JsValue> {
100                exports::on_transaction(transaction, chainid, req).await
101            }
102
103            #[wasm_bindgen::prelude::wasm_bindgen]
104            pub async fn on_cronjob(method: &str, params: JsValue) -> JsResult<JsValue> {
105                exports::on_cronjob(method, params).await
106            }
107        }
108    };
109
110    TokenStream::from(expanded)
111}