1extern crate proc_macro;
2use proc_macro::TokenStream;
3use quote::{format_ident, quote};
4use syn::{ItemFn, LitStr, parse_macro_input};
5
6#[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#[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}