wasm_rpc_macros/
lib.rs

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}