lib.rs

  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}