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 export(args: TokenStream, function: TokenStream) -> TokenStream {
9 if !args.is_empty() {
10 panic!("The export 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 export 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 // TODO: switch len from usize to u32?
57 pub extern "C" fn #outer_fn_name(ptr: *const u8, len: usize) -> *const ::plugin::__Buffer {
58 // setup
59 let buffer = ::plugin::__Buffer { ptr, len };
60 let data = unsafe { buffer.to_vec() };
61
62 // operation
63 let data: #ty = match ::plugin::bincode::deserialize(&data) {
64 Ok(d) => d,
65 Err(e) => panic!("Data passed to function not deserializable."),
66 };
67 let result = #inner_fn_name(#args);
68 let new_data: Result<Vec<u8>, _> = ::plugin::bincode::serialize(&result);
69 let new_data = new_data.unwrap();
70
71 // teardown
72 let new_buffer = unsafe { ::plugin::__Buffer::from_vec(new_data) };
73 return new_buffer.leak_to_heap();
74 }
75 })
76}
77
78#[proc_macro_attribute]
79pub fn import(args: TokenStream, function: TokenStream) -> TokenStream {
80 todo!()
81 // if !args.is_empty() {
82 // panic!("The import attribute does not take any arguments");
83 // }
84
85 // let inner_fn = parse_macro_input!(function as ItemFn);
86
87 // let inner_fn_name = format_ident!("{}", inner_fn.sig.ident);
88 // // let outer_fn_name = format_ident!("__{}", inner_fn_name);
89
90 // let variadic = inner_fn.sig.inputs.len();
91 // let i = (0..variadic).map(syn::Index::from);
92 // let t: Vec<Type> = inner_fn
93 // .sig
94 // .inputs
95 // .iter()
96 // .map(|x| match x {
97 // FnArg::Receiver(_) => {
98 // panic!("all arguments must have specified types, no `self` allowed")
99 // }
100 // FnArg::Typed(item) => *item.ty.clone(),
101 // })
102 // .collect();
103
104 // // this is cursed...
105 // let (args, ty) = if variadic != 1 {
106 // (
107 // quote! {
108 // #( data.#i ),*
109 // },
110 // quote! {
111 // ( #( #t ),* )
112 // },
113 // )
114 // } else {
115 // let ty = &t[0];
116 // (quote! { data }, quote! { #ty })
117 // };
118
119 // TokenStream::from(quote! {
120 // #[no_mangle]
121 // #inner_fn
122
123 // #[no_mangle]
124 // pub extern "C" fn #outer_fn_name(ptr: *const u8, len: usize) -> *const ::plugin::__Buffer {
125 // // setup
126 // let buffer = ::plugin::__Buffer { ptr, len };
127 // let data = unsafe { buffer.to_vec() };
128
129 // // operation
130 // let data: #ty = match ::plugin::bincode::deserialize(&data) {
131 // Ok(d) => d,
132 // Err(e) => panic!("Data passed to function not deserializable."),
133 // };
134 // let result = #inner_fn_name(#args);
135 // let new_data: Result<Vec<u8>, _> = ::plugin::bincode::serialize(&result);
136 // let new_data = new_data.unwrap();
137
138 // // teardown
139 // let new_buffer = unsafe { ::plugin::__Buffer::from_vec(new_data) };
140 // return new_buffer.leak_to_heap();
141 // }
142 // })
143}