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