1#[macro_use]
13extern crate quote;
14
15use proc_macro::TokenStream;
16
17use syn::spanned::Spanned;
18use syn::{parse, ImplItemMethod, ItemImpl, ItemTrait, Token};
19
20fn add_async_trait(mut parsed: ItemTrait) -> TokenStream {
21 let output = quote! {
22 #[cfg(all(not(target_arch = "wasm32"), not(feature = "async-interface")))]
23 #parsed
24 };
25
26 for mut item in &mut parsed.items {
27 if let syn::TraitItem::Method(m) = &mut item {
28 m.sig.asyncness = Some(Token));
29 }
30 }
31
32 let output = quote! {
33 #output
34
35 #[cfg(any(target_arch = "wasm32", feature = "async-interface"))]
36 #[async_trait(?Send)]
37 #parsed
38 };
39
40 output.into()
41}
42
43fn add_async_method(mut parsed: ImplItemMethod) -> TokenStream {
44 let output = quote! {
45 #[cfg(all(not(target_arch = "wasm32"), not(feature = "async-interface")))]
46 #parsed
47 };
48
49 parsed.sig.asyncness = Some(Token));
50
51 let output = quote! {
52 #output
53
54 #[cfg(any(target_arch = "wasm32", feature = "async-interface"))]
55 #parsed
56 };
57
58 output.into()
59}
60
61fn add_async_impl_trait(mut parsed: ItemImpl) -> TokenStream {
62 let output = quote! {
63 #[cfg(all(not(target_arch = "wasm32"), not(feature = "async-interface")))]
64 #parsed
65 };
66
67 for mut item in &mut parsed.items {
68 if let syn::ImplItem::Method(m) = &mut item {
69 m.sig.asyncness = Some(Token));
70 }
71 }
72
73 let output = quote! {
74 #output
75
76 #[cfg(any(target_arch = "wasm32", feature = "async-interface"))]
77 #[async_trait(?Send)]
78 #parsed
79 };
80
81 output.into()
82}
83
84#[proc_macro_attribute]
89pub fn maybe_async(_attr: TokenStream, item: TokenStream) -> TokenStream {
90 if let Ok(parsed) = parse(item.clone()) {
91 add_async_trait(parsed)
92 } else if let Ok(parsed) = parse(item.clone()) {
93 add_async_method(parsed)
94 } else if let Ok(parsed) = parse(item) {
95 add_async_impl_trait(parsed)
96 } else {
97 (quote! {
98 compile_error!("#[maybe_async] can only be used on methods, trait or trait impl blocks")
99 })
100 .into()
101 }
102}
103
104#[proc_macro]
106pub fn maybe_await(expr: TokenStream) -> TokenStream {
107 let expr: proc_macro2::TokenStream = expr.into();
108 let quoted = quote! {
109 {
110 #[cfg(all(not(target_arch = "wasm32"), not(feature = "async-interface")))]
111 {
112 #expr
113 }
114
115 #[cfg(any(target_arch = "wasm32", feature = "async-interface"))]
116 {
117 #expr.await
118 }
119 }
120 };
121
122 quoted.into()
123}
124
125#[proc_macro]
129pub fn await_or_block(expr: TokenStream) -> TokenStream {
130 let expr: proc_macro2::TokenStream = expr.into();
131 let quoted = quote! {
132 {
133 #[cfg(all(not(target_arch = "wasm32"), not(feature = "async-interface")))]
134 {
135 tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(#expr)
136 }
137
138 #[cfg(any(target_arch = "wasm32", feature = "async-interface"))]
139 {
140 #expr.await
141 }
142 }
143 };
144
145 quoted.into()
146}