ayaka_bindings_impl/
lib.rs1use 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}