zetax_macro/
lib.rs

1extern crate proc_macro;
2use proc_macro::TokenStream;
3use quote::{format_ident, quote};
4use syn::{ItemFn, LitStr, parse_macro_input};
5
6/// #[rpc("name")]
7#[proc_macro_attribute]
8pub fn rpc(attr: TokenStream, item: TokenStream) -> TokenStream {
9    let input_fn = parse_macro_input!(item as ItemFn);
10    let name_lit = parse_macro_input!(attr as LitStr);
11    let rpc_name = name_lit.value();
12
13    let fn_ident = &input_fn.sig.ident;
14    let struct_ident = format_ident!("__Rpc_{}", fn_ident);
15    let static_ident = format_ident!("RPC_{}", fn_ident.to_string().to_uppercase());
16
17    let expanded = quote! {
18        #input_fn
19
20        #[allow(non_camel_case_types)]
21        pub struct #struct_ident;
22
23        impl ::zetax_types::handlers::Rpc for #struct_ident {
24            fn name(&self) -> &'static str { #rpc_name }
25            fn call(&self,
26                    ctx: ::zetax_types::handlers::RpcContext,
27                    input: ::std::vec::Vec<u8>)
28                -> ::zetax_types::handlers::RpcFut
29            {
30                ::zetax_types::handlers::RpcBox::boxed(async move {
31                    #fn_ident(ctx, input).await
32                })
33            }
34        }
35
36        #[allow(non_upper_case_globals)]
37        pub static #static_ident: #struct_ident = #struct_ident;
38    };
39
40    TokenStream::from(expanded)
41}
42
43/// #[rstream("name")]
44#[proc_macro_attribute]
45pub fn rstream(attr: TokenStream, item: TokenStream) -> TokenStream {
46    let input_fn = parse_macro_input!(item as ItemFn);
47    let name_lit = parse_macro_input!(attr as LitStr);
48    let rpc_name = name_lit.value();
49
50    let fn_ident = &input_fn.sig.ident;
51    let struct_ident = format_ident!("__RpcStream_{}", fn_ident);
52    let static_ident = format_ident!("RPC_STREAM_{}", fn_ident.to_string().to_uppercase());
53
54    let expanded = quote! {
55        #input_fn
56
57        #[allow(non_camel_case_types)]
58        pub struct #struct_ident;
59
60        impl ::zetax_types::handlers::RpcStream for #struct_ident {
61            fn name(&self) -> &'static str { #rpc_name }
62            fn call_stream(
63                &self,
64                ctx: ::zetax_types::handlers::RpcContext,
65                input: ::std::vec::Vec<u8>
66            ) -> ::zetax_types::handlers::RpcStreamFut {
67                ::zetax_types::handlers::RpcStreamBox::boxed(async move {
68                    #fn_ident(ctx, input).await
69                })
70            }
71        }
72
73        #[allow(non_upper_case_globals)]
74        pub static #static_ident: #struct_ident = #struct_ident;
75    };
76
77    TokenStream::from(expanded)
78}
79
80#[proc_macro_attribute]
81pub fn capnp(attr: TokenStream, item: TokenStream) -> TokenStream {
82    let input_fn = parse_macro_input!(item as ItemFn);
83    let name_lit = parse_macro_input!(attr as LitStr);
84    let rpc_name = name_lit.value();
85
86    let fn_ident = &input_fn.sig.ident;
87    let struct_ident = format_ident!("__CapnpRpc_{}", fn_ident);
88    let static_ident = format_ident!("CAPNP_RPC_{}", fn_ident.to_string().to_uppercase());
89
90    let expanded = quote! {
91        #input_fn
92
93        #[allow(non_camel_case_types)]
94        pub struct #struct_ident;
95
96        impl ::zetax_types::handlers::Rpc for #struct_ident {
97            fn name(&self) -> &'static str { #rpc_name }
98
99            fn call(
100                &self,
101                ctx: ::zetax_types::handlers::RpcContext,
102                input: ::std::vec::Vec<u8>
103            ) -> ::zetax_types::handlers::RpcFut {
104                ::zetax_types::handlers::RpcBox::boxed(async move {
105                    let message_reader = ::capnp::serialize::read_message(
106                        &mut &input[..],
107                        ::capnp::message::ReaderOptions::new()
108                    ).map_err(|e| {
109                        Box::new(::zetax_types::errors::RpcError::Deserialization(e.to_string()))
110                            as Box<dyn ::std::error::Error + Send + Sync>
111                    })?;
112
113                    let response_message = #fn_ident(ctx, message_reader)
114                        .await
115                        .map_err(|e| Box::new(e) as Box<dyn ::std::error::Error + Send + Sync>)?;
116
117                    let mut buf: ::std::vec::Vec<u8> = ::std::vec::Vec::new();
118                    ::capnp::serialize::write_message(&mut buf, &response_message).map_err(|e| {
119                        Box::new(::zetax_types::errors::RpcError::Serialization(e.to_string()))
120                            as Box<dyn ::std::error::Error + Send + Sync>
121                    })?;
122
123                    Ok(buf)
124                })
125            }
126        }
127
128        #[allow(non_upper_case_globals)]
129        pub static #static_ident: #struct_ident = #struct_ident;
130    };
131
132    TokenStream::from(expanded)
133}