1use core::panic;
2
3use proc_macro::TokenStream;
4use quote::{format_ident, quote};
5use syn::{parse_macro_input, FnArg, ForeignItemFn, 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
15 if !inner_fn.sig.generics.params.is_empty() {
16 panic!("Exported functions can not take generic parameters");
17 }
18
19 if let Visibility::Public(_) = inner_fn.vis {
20 } else {
21 panic!("The export attribute only works for public functions");
22 }
23
24 let inner_fn_name = format_ident!("{}", inner_fn.sig.ident);
25 let outer_fn_name = format_ident!("__{}", inner_fn_name);
26
27 let variadic = inner_fn.sig.inputs.len();
28 let i = (0..variadic).map(syn::Index::from);
29 let t: Vec<Type> = inner_fn
30 .sig
31 .inputs
32 .iter()
33 .map(|x| match x {
34 FnArg::Receiver(_) => {
35 panic!("all arguments must have specified types, no `self` allowed")
36 }
37 FnArg::Typed(item) => *item.ty.clone(),
38 })
39 .collect();
40
41 // this is cursed...
42 let (args, ty) = if variadic != 1 {
43 (
44 quote! {
45 #( data.#i ),*
46 },
47 quote! {
48 ( #( #t ),* )
49 },
50 )
51 } else {
52 let ty = &t[0];
53 (quote! { data }, quote! { #ty })
54 };
55
56 TokenStream::from(quote! {
57 #[no_mangle]
58 #inner_fn
59
60 #[no_mangle]
61 // TODO: switch len from usize to u32?
62 pub extern "C" fn #outer_fn_name(packed_buffer: u64) -> u64 {
63 // setup
64 let data = unsafe { ::plugin::__Buffer::from_u64(packed_buffer).to_vec() };
65
66 // operation
67 let data: #ty = match ::plugin::bincode::deserialize(&data) {
68 Ok(d) => d,
69 Err(e) => panic!("Data passed to function not deserializable."),
70 };
71 let result = #inner_fn_name(#args);
72 let new_data: Result<Vec<u8>, _> = ::plugin::bincode::serialize(&result);
73 let new_data = new_data.unwrap();
74
75 // teardown
76 let new_buffer = unsafe { ::plugin::__Buffer::from_vec(new_data) }.into_u64();
77 return new_buffer;
78 }
79 })
80}
81
82#[proc_macro_attribute]
83pub fn import(args: TokenStream, function: TokenStream) -> TokenStream {
84 if !args.is_empty() {
85 panic!("The import attribute does not take any arguments");
86 }
87
88 let fn_declare = parse_macro_input!(function as ForeignItemFn);
89
90 if !fn_declare.sig.generics.params.is_empty() {
91 panic!("Exported functions can not take generic parameters");
92 }
93
94 dbg!(&fn_declare.sig);
95
96 // let inner_fn = ItemFn {
97 // attrs: fn_declare.attrs,
98 // vis: fn_declare.vis,
99 // sig: fn_declare.sig,
100 // block: todo!(),
101 // };
102
103 let outer_fn_name = format_ident!("{}", fn_declare.sig.ident);
104 let inner_fn_name = format_ident!("__{}", outer_fn_name);
105
106 // let variadic = inner_fn.sig.inputs.len();
107 // let i = (0..variadic).map(syn::Index::from);
108 // let t: Vec<Type> = inner_fn
109 // .sig
110 // .inputs
111 // .iter()
112 // .map(|x| match x {
113 // FnArg::Receiver(_) => {
114 // panic!("all arguments must have specified types, no `self` allowed")
115 // }
116 // FnArg::Typed(item) => *item.ty.clone(),
117 // })
118 // .collect();
119
120 // // this is cursed...
121 // let (args, ty) = if variadic != 1 {
122 // (
123 // quote! {
124 // #( data.#i ),*
125 // },
126 // quote! {
127 // ( #( #t ),* )
128 // },
129 // )
130 // } else {
131 // let ty = &t[0];
132 // (quote! { data }, quote! { #ty })
133 // };
134
135 // TokenStream::from(quote! {
136 // extern "C" {
137 // fn #inner_fn_name(buffer: u64) -> u64;
138 // }
139
140 // #[no_mangle]
141 // fn #outer_fn_name #args /* (string: &str) */ -> #return_type /* Option<Vec<u8>> */ {
142 // dbg!("executing command: {}", string);
143 // // setup
144 // let data = #args_collect;
145 // let data = ::plugin::bincode::serialize(&data).unwrap();
146 // let buffer = unsafe { ::plugin::__Buffer::from_vec(data) };
147
148 // // operation
149 // let new_buffer = unsafe { #inner_fn_name(buffer.into_u64()) };
150 // let new_data = unsafe { ::plugin::__Buffer::from_u64(new_buffer).to_vec() };
151
152 // // teardown
153 // match ::plugin::bincode::deserialize(&new_data) {
154 // Ok(d) => d,
155 // Err(e) => panic!("Data returned from function not deserializable."),
156 // }
157 // }
158 // })
159 todo!()
160}