1use generator::ProceduresGenerator;
2use proc::{IpcMethod, Procedures};
3use proc_macro::{self, TokenStream};
4use quote::{ToTokens, format_ident, quote};
5use syn::{
6 Ident, ImplItem, ImplItemFn, ImplItemType, ItemImpl, ItemStruct, ReturnType, Type,
7 parse_macro_input, parse_quote, parse_quote_spanned, spanned::Spanned,
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::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 path_prefix: procedures_attrs.path,
66 inputs_ident: &format_ident!("TauRpc{}Inputs", ident),
67 outputs_ident: &format_ident!("TauRpc{}Outputs", ident),
68 output_futures_ident: &format_ident!("TauRpc{}OutputFutures", ident),
69 methods,
70 method_output_types: &methods
71 .iter()
72 .map(|IpcMethod { output, .. }| match output {
73 ReturnType::Type(_, ref ty) => ty,
74 ReturnType::Default => unit_type,
75 })
76 .collect::<Vec<_>>(),
77 alias_method_idents: &methods
78 .iter()
79 .map(|IpcMethod { ident, attrs, .. }| {
80 attrs
81 .alias
82 .as_ref()
83 .map(|alias| Ident::new(alias, ident.span()))
84 .unwrap_or(ident.clone())
85 })
86 .collect::<Vec<_>>(),
87 vis,
88 generics,
89 attrs,
90 }
91 .into_token_stream()
92 .into()
93}
94
95#[proc_macro_attribute]
97pub fn resolvers(_attr: TokenStream, item: TokenStream) -> TokenStream {
98 let mut item = syn::parse_macro_input!(item as ItemImpl);
99 let mut types: Vec<ImplItemType> = Vec::new();
100
101 for inner in &mut item.items {
102 if let ImplItem::Fn(method) = inner {
103 if method.sig.asyncness.is_some() {
104 types.push(transform_method(method));
105 }
106 }
107 }
108
109 for t in types.into_iter() {
111 item.items.push(syn::ImplItem::Type(t));
112 }
113
114 quote! {
115 #[allow(non_camel_case_types)]
116 #item
117 }
118 .into()
119}
120
121fn transform_method(method: &mut ImplItemFn) -> ImplItemType {
123 method.sig.asyncness = None;
124
125 let ret = match &method.sig.output {
126 ReturnType::Default => quote!(()),
127 ReturnType::Type(_, ret) => quote!(#ret),
128 };
129
130 let fut_ident = method_fut_ident(&method.sig.ident);
131
132 method.sig.output = parse_quote! {
133 -> ::core::pin::Pin<Box<
134 dyn ::core::future::Future<Output = #ret> + ::core::marker::Send
135 >>
136 };
137
138 let block = method.block.clone();
140 method.block = parse_quote_spanned! {method.span()=>{
141 Box::pin(async move #block)
142 }};
143
144 let t = parse_quote! {
146 type #fut_ident = ::core::pin::Pin<Box<dyn ::core::future::Future<Output = #ret> + ::core::marker::Send>>;
147 };
148
149 t
150}
151
152fn method_fut_ident(ident: &Ident) -> Ident {
153 format_ident!("{}Fut", ident)
154}