1use generator::ProceduresGenerator;
2use proc::{IpcMethod, Procedures};
3use proc_macro::{self, TokenStream};
4use quote::{format_ident, quote, ToTokens};
5use syn::{
6 parse_macro_input, parse_quote, parse_quote_spanned, spanned::Spanned, Ident, ImplItem,
7 ImplItemFn, ImplItemType, ItemImpl, ItemStruct, ReturnType, Type,
8};
9
10mod args;
11mod attrs;
12mod generator;
13mod proc;
14
15use crate::attrs::ProceduresAttrs;
16
17macro_rules! extend_errors {
22 ($errors: ident, $e: expr) => {
23 match $errors {
24 Ok(_) => $errors = Err($e),
25 Err(ref mut errors) => errors.extend($e),
26 }
27 };
28}
29pub(crate) use extend_errors;
30
31#[proc_macro_attribute]
34pub fn ipc_type(_attr: TokenStream, item: TokenStream) -> TokenStream {
35 let input = parse_macro_input!(item as ItemStruct);
36
37 quote! {
38 #[derive(taurpc::serde::Serialize, taurpc::serde::Deserialize, taurpc::specta_macros::Type, Clone)]
39 #input
40 }
41 .into()
42}
43
44#[proc_macro_attribute]
46pub fn procedures(attrs: TokenStream, item: TokenStream) -> TokenStream {
47 let procedures_attrs = parse_macro_input!(attrs as ProceduresAttrs);
48
49 let Procedures {
50 ref ident,
51 ref methods,
52 ref vis,
53 ref generics,
54 ref attrs,
55 } = parse_macro_input!(item as Procedures);
56
57 let unit_type: &Type = &parse_quote!(());
58
59 ProceduresGenerator {
60 trait_ident: ident,
61 handler_ident: &format_ident!("TauRpc{}Handler", ident),
62 event_trigger_ident: &procedures_attrs
63 .event_trigger_ident
64 .unwrap_or(format_ident!("TauRpc{}EventTrigger", ident)),
65 export_path: procedures_attrs.export_to,
66 path_prefix: procedures_attrs.path,
67 inputs_ident: &format_ident!("TauRpc{}Inputs", ident),
68 outputs_ident: &format_ident!("TauRpc{}Outputs", ident),
69 output_futures_ident: &format_ident!("TauRpc{}OutputFutures", ident),
70 methods,
71 method_output_types: &methods
72 .iter()
73 .map(|IpcMethod { output, .. }| match output {
74 ReturnType::Type(_, ref ty) => ty,
75 ReturnType::Default => unit_type,
76 })
77 .collect::<Vec<_>>(),
78 alias_method_idents: &methods
79 .iter()
80 .map(|IpcMethod { ident, attrs, .. }| {
81 attrs
82 .alias
83 .as_ref()
84 .map(|alias| Ident::new(alias, ident.span()))
85 .unwrap_or(ident.clone())
86 })
87 .collect::<Vec<_>>(),
88 vis,
89 generics,
90 attrs,
91 }
92 .into_token_stream()
93 .into()
94}
95
96#[proc_macro_attribute]
98pub fn resolvers(_attr: TokenStream, item: TokenStream) -> TokenStream {
99 let mut item = syn::parse_macro_input!(item as ItemImpl);
100 let mut types: Vec<ImplItemType> = Vec::new();
101
102 for inner in &mut item.items {
103 if let ImplItem::Fn(method) = inner {
104 if method.sig.asyncness.is_some() {
105 types.push(transform_method(method));
106 }
107 }
108 }
109
110 for t in types.into_iter() {
112 item.items.push(syn::ImplItem::Type(t));
113 }
114
115 quote!(#item).into()
116}
117
118fn transform_method(method: &mut ImplItemFn) -> ImplItemType {
120 method.sig.asyncness = None;
121
122 let ret = match &method.sig.output {
123 ReturnType::Default => quote!(()),
124 ReturnType::Type(_, ret) => quote!(#ret),
125 };
126
127 let fut_ident = method_fut_ident(&method.sig.ident);
128
129 method.sig.output = parse_quote! {
130 -> ::core::pin::Pin<Box<
131 dyn ::core::future::Future<Output = #ret> + ::core::marker::Send
132 >>
133 };
134
135 let block = method.block.clone();
137 method.block = parse_quote_spanned! {method.span()=>{
138 Box::pin(async move #block)
139 }};
140
141 let t = parse_quote! {
143 type #fut_ident = ::core::pin::Pin<Box<dyn ::core::future::Future<Output = #ret> + ::core::marker::Send>>;
144 };
145
146 t
147}
148
149fn method_fut_ident(ident: &Ident) -> Ident {
150 format_ident!("{}Fut", ident)
151}