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(ptr: *const u8, len: usize) -> *const ::plugin::__Buffer {
63 // setup
64 let buffer = ::plugin::__Buffer { ptr, len };
65 let data = unsafe { buffer.to_vec() };
66
67 // operation
68 let data: #ty = match ::plugin::bincode::deserialize(&data) {
69 Ok(d) => d,
70 Err(e) => panic!("Data passed to function not deserializable."),
71 };
72 let result = #inner_fn_name(#args);
73 let new_data: Result<Vec<u8>, _> = ::plugin::bincode::serialize(&result);
74 let new_data = new_data.unwrap();
75
76 // teardown
77 let new_buffer = unsafe { ::plugin::__Buffer::from_vec(new_data) };
78 return new_buffer.leak_to_heap();
79 }
80 })
81}
82
83#[proc_macro_attribute]
84pub fn import(args: TokenStream, function: TokenStream) -> TokenStream {
85 if !args.is_empty() {
86 panic!("The import attribute does not take any arguments");
87 }
88
89 let fn_declare = parse_macro_input!(function as ForeignItemFn);
90
91 if !fn_declare.sig.generics.params.is_empty() {
92 panic!("Exported functions can not take generic parameters");
93 }
94
95 dbg!(&fn_declare.sig);
96
97 // let inner_fn = ItemFn {
98 // attrs: fn_declare.attrs,
99 // vis: fn_declare.vis,
100 // sig: fn_declare.sig,
101 // block: todo!(),
102 // };
103
104 // let inner_fn_name = format_ident!("{}", inner_fn.sig.ident);
105 // let outer_fn_name = format_ident!("__{}", inner_fn_name);
106
107 // let variadic = inner_fn.sig.inputs.len();
108 // let i = (0..variadic).map(syn::Index::from);
109 // let t: Vec<Type> = inner_fn
110 // .sig
111 // .inputs
112 // .iter()
113 // .map(|x| match x {
114 // FnArg::Receiver(_) => {
115 // panic!("all arguments must have specified types, no `self` allowed")
116 // }
117 // FnArg::Typed(item) => *item.ty.clone(),
118 // })
119 // .collect();
120
121 // // this is cursed...
122 // let (args, ty) = if variadic != 1 {
123 // (
124 // quote! {
125 // #( data.#i ),*
126 // },
127 // quote! {
128 // ( #( #t ),* )
129 // },
130 // )
131 // } else {
132 // let ty = &t[0];
133 // (quote! { data }, quote! { #ty })
134 // };
135
136 // TokenStream::from(quote! {
137 // extern "C" {
138 // #[no_mangle]
139 // fn #outer_fn_name(ptr: *const u8, len: usize) -> *const ::plugin::__Buffer;
140 // }
141
142 // #[no_mangle]
143 // fn #inner_fn_name #params -> #output {
144 // println!("executing command: {}", string);
145 // // serialize data
146 // let data = #collect_params;
147 // let data = ::plugin::bincode::serialize(&data).unwrap();
148 // let buffer = unsafe { ::plugin::__Buffer::from_vec(data) };
149 // let ptr = buffer.ptr;
150 // let len = buffer.len;
151 // // leak data to heap
152 // buffer.leak_to_heap();
153 // // call extern function
154 // let result = unsafe { __command(ptr, len) };
155 // // get result
156 // let result = todo!(); // convert into box
157
158 // // deserialize data
159 // let data: Option<String> = match ::plugin::bincode::deserialize(&data) {
160 // Ok(d) => d,
161 // Err(e) => panic!("Data passed to function not deserializable."),
162 // };
163 // return data;
164 // }
165 // })
166 todo!()
167}