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(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}