1#[macro_use]
2extern crate quote;
3extern crate proc_macro;
4extern crate syn;
5
6mod native;
7
8use syn::{
9 parse::{Parse, ParseStream},
10 parse_macro_input, parse_quote, FnArg, ItemFn, Result, Signature,
11};
12
13#[proc_macro]
14pub fn export_native(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
15 native::export_native(tokens)
16}
17
18#[proc_macro]
19pub fn export(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
20 let Exported::Fns(mut fns) = parse_macro_input!(tokens as Exported);
21 if cfg!(debug_assertions) {
22 return quote!(#(#fns)*).into();
23 };
24 for f in fns.iter_mut() {
25 replace_values_with_pointers(f);
26 return_null(f);
27 }
28 quote!(#(#fns)*).into()
29}
30
31enum Exported {
32 Fns(Vec<syn::ItemFn>),
33}
34
35impl Parse for Exported {
36 fn parse(input: ParseStream) -> Result<Self> {
37 Ok(Exported::Fns(
38 syn::Block::parse_within(input)
39 .unwrap()
40 .iter()
41 .cloned()
42 .filter_map(|stmt| {
43 if let syn::Stmt::Item(syn::Item::Fn(f)) = stmt {
44 Some(f)
45 } else {
46 None
47 }
48 })
49 .collect::<Vec<syn::ItemFn>>(),
50 ))
51 }
52}
53
54fn return_null<'a>(f: &'a mut ItemFn) {
55 if f.sig.output == parse_quote!() {
56 f.sig.output = parse_quote!(-> wasm_rpc::Pointer);
57 f.block.stmts.push(syn::Stmt::Expr(parse_quote!(
58 wasm_rpc::serde_cbor::Value::Null
59 )));
60 }
61}
62
63fn replace_values_with_pointers(f: &mut ItemFn) {
64 let ItemFn {
65 sig: Signature { inputs, output, .. },
66 block,
67 ..
68 } = f.clone();
69 let pointers: Vec<syn::ExprMethodCall> = f
70 .sig
71 .inputs
72 .clone()
73 .into_iter()
74 .map(&pointer_to_value)
75 .collect();
76 f.attrs.push(parse_quote!(#[no_mangle]));
77 f.block =
78 parse_quote!({wasm_rpc::pointer::from_value(&(|#inputs|#output #block)(#(#pointers),*))});
79 f.sig.inputs = f
80 .sig
81 .inputs
82 .iter()
83 .cloned()
84 .map(|input| {
85 if let FnArg::Typed(mut pat) = input {
86 pat.ty = parse_quote!(wasm_rpc::Pointer);
87 FnArg::Typed(pat)
88 } else {
89 input
90 }
91 })
92 .collect();
93 f.sig.output = parse_quote!(-> wasm_rpc::Pointer);
94}
95
96fn pointer_to_value(input: FnArg) -> syn::ExprMethodCall {
97 if let FnArg::Typed(syn::PatType { pat, .. }) = input {
98 parse_quote!(wasm_rpc::pointer::to_value(#pat).unwrap())
99 } else {
100 parse_quote!(#input)
101 }
102}