lib.rs

 1use core::panic;
 2
 3use proc_macro::TokenStream;
 4use quote::{format_ident, quote};
 5use syn::{parse_macro_input, FnArg, ItemFn, Type, Visibility};
 6
 7#[proc_macro_attribute]
 8pub fn bind(args: TokenStream, function: TokenStream) -> TokenStream {
 9    if !args.is_empty() {
10        panic!("The bind attribute does not take any arguments");
11    }
12
13    let inner_fn = parse_macro_input!(function as ItemFn);
14    if let Visibility::Public(_) = inner_fn.vis {
15    } else {
16        panic!("The bind attribute only works for public functions");
17    }
18
19    let inner_fn_name = format_ident!("{}", inner_fn.sig.ident);
20    let outer_fn_name = format_ident!("__{}", inner_fn_name);
21
22    let variadic = inner_fn.sig.inputs.len();
23    let i = (0..variadic).map(syn::Index::from);
24    let t: Vec<Type> = inner_fn
25        .sig
26        .inputs
27        .iter()
28        .map(|x| match x {
29            FnArg::Receiver(_) => {
30                panic!("all arguments must have specified types, no `self` allowed")
31            }
32            FnArg::Typed(item) => *item.ty.clone(),
33        })
34        .collect();
35
36    // this is cursed...
37    let (args, ty) = if variadic != 1 {
38        (
39            quote! {
40                #( data.#i ),*
41            },
42            quote! {
43                ( #( #t ),* )
44            },
45        )
46    } else {
47        let ty = &t[0];
48        (quote! { data }, quote! { #ty })
49    };
50
51    TokenStream::from(quote! {
52        #[no_mangle]
53        #inner_fn
54
55        #[no_mangle]
56        pub extern "C" fn #outer_fn_name(ptr: *const u8, len: usize) -> *const ::plugin::__Buffer {
57            // setup
58            let buffer = ::plugin::__Buffer { ptr, len };
59            let data = unsafe { buffer.to_vec() };
60
61            // operation
62            let data: #ty = match ::plugin::bincode::deserialize(&data) {
63                Ok(d) => d,
64                Err(e) => panic!("Data passed to function not deserializable."),
65            };
66            let result = #inner_fn_name(#args);
67            let new_data: Result<Vec<u8>, _> = ::plugin::bincode::serialize(&result);
68            let new_data = new_data.unwrap();
69
70            // teardown
71            let new_buffer = unsafe { ::plugin::__Buffer::from_vec(new_data) };
72            return new_buffer.leak_to_heap();
73        }
74    })
75}