ayaka_bindings_impl/
lib.rs

1use proc_macro::TokenStream;
2use proc_macro_crate::{crate_name, FoundCrate};
3use quote::{quote, TokenStreamExt};
4use syn::{parse_macro_input, parse_str, FnArg, ForeignItem, Ident, ItemFn, ItemForeignMod, Lit};
5
6#[proc_macro_attribute]
7pub fn export(_attr: TokenStream, input: TokenStream) -> TokenStream {
8    let func = input.clone();
9    let func = parse_macro_input!(func as ItemFn);
10    let name = func.sig.ident;
11    let name_str = name.to_string();
12    let expname = parse_str::<Ident>(&format!("__export_{}", name_str)).unwrap();
13    let input = proc_macro2::TokenStream::from(input);
14    let export_func = quote! {
15        #[doc(hidden)]
16        #[export_name = #name_str]
17        extern "C" fn #expname(len: usize, data: *const u8) -> u64 {
18            ::ayaka_bindings::__export(len, data, #name)
19        }
20        #input
21    };
22    TokenStream::from(export_func)
23}
24
25#[proc_macro_attribute]
26pub fn import(attr: TokenStream, input: TokenStream) -> TokenStream {
27    let attr = parse_macro_input!(attr as Lit);
28    let module = match attr {
29        Lit::Str(str) => str.value(),
30        _ => unimplemented!(),
31    };
32    let input = parse_macro_input!(input as ItemForeignMod);
33    let mut imports = quote! {};
34    for func in input.items {
35        match func {
36            ForeignItem::Fn(func) => {
37                let attrs = func.attrs;
38                let vis = func.vis;
39                let sig = func.sig;
40
41                let params = sig.inputs.clone();
42                let params = params
43                    .into_iter()
44                    .map(|arg| match arg {
45                        FnArg::Typed(p) => p.pat,
46                        _ => unimplemented!(),
47                    })
48                    .collect::<Vec<_>>();
49
50                let name = sig.ident.clone();
51                let name_str = name.to_string();
52                let impname = parse_str::<Ident>(&format!("__import_{}", name_str)).unwrap();
53                let bindings_crate_name = match crate_name("ayaka-bindings").unwrap() {
54                    FoundCrate::Itself => quote!(crate),
55                    FoundCrate::Name(name) => {
56                        let name = parse_str::<Ident>(&name).unwrap();
57                        quote!(::#name)
58                    }
59                };
60                let import_func = quote! {
61                    #[doc(hidden)]
62                    #[link(wasm_import_module = #module)]
63                    extern "C" {
64                        #[link_name = #name_str]
65                        fn #impname(len: usize, data: *const u8) -> u64;
66                    }
67                    #(#attrs)* #vis #sig {
68                        #bindings_crate_name::__import(#impname, (#(#params,)*))
69                    }
70                };
71                imports.append_all(import_func);
72            }
73            _ => unimplemented!(),
74        }
75    }
76    TokenStream::from(imports)
77}