1extern crate proc_macro;
2use proc_macro::TokenStream;
3use proc_macro2::Ident;
4use quote::quote;
5use syn::{ItemEnum, ItemFn, ItemStruct, ItemType, ReturnType};
6
7fn wasmbox_impl(item: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
8 let func: ItemFn = syn::parse2(item.clone()).expect("#[wasmbox] should annotate a function.");
9
10 if &func.sig.ident.to_string() != "run" {
11 panic!("#[wasmbox] should annotate a function called `run`.");
12 }
13
14 if func.sig.asyncness.is_none() {
15 panic!("#[wasmbox] should annotate an async function.");
16 }
17
18 if let ReturnType::Default = func.sig.output {
19 } else {
20 panic!("The function wrapped by #[wasmbox] should not have a return type.");
21 }
22
23 let inputs: Vec<_> = func.sig.inputs.iter().collect();
24 if inputs.len() != 1 {
25 panic!("The function wrapped by #[wasmbox] should have exactly one argument (a WasmboxContext.)");
26 }
27
28 let inputs = func.sig.inputs;
29 let block = func.block;
30
31 quote! {
32 mod _wasmbox_macro_autogenerated {
33 use super::*;
34 use wasmbox::prelude::*;
35 use std::pin::Pin;
36 use std::boxed::Box;
37 use std::future::Future;
38
39 #[derive(Default)]
40 struct WasmBoxImpl;
41
42 impl AsyncWasmBox for WasmBoxImpl {
43 type Input = String;
44 type Output = String;
45
46 fn run<'async_trait>(#inputs) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>> where
47 Self: 'async_trait
48 {
49 Box::pin(async move {
50 #block
51 })
52 }
53 }
54
55 #[no_mangle]
56 extern "C" fn wasmbox_initialize() {
57 initialize_async::<WasmBoxImpl>();
58 }
59 }
60 }
61}
62
63fn get_name(item: &proc_macro2::TokenStream) -> Option<Ident> {
64 let ident = if let Ok(ItemStruct { ident, .. }) = syn::parse2(item.clone()) {
65 ident
66 } else if let Ok(ItemEnum { ident, .. }) = syn::parse2(item.clone()) {
67 ident
68 } else if let Ok(ItemType { ident, .. }) = syn::parse2(item.clone()) {
69 ident
70 } else {
71 return None;
72 };
73
74 Some(ident)
75}
76
77fn wasmbox_sync_impl(item: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
78 let ident: Ident = get_name(&item)
79 .expect("Item decorated by #[wasmbox_sync] should be a struct, enum, or type.");
80
81 quote! {
82 #item
83
84 use wasmbox::prelude::initialize;
85
86 #[no_mangle]
87 extern "C" fn wasmbox_initialize() {
88 initialize::<#ident>();
89 }
90 }
91}
92
93#[proc_macro_attribute]
94pub fn wasmbox(_attr: TokenStream, item: TokenStream) -> TokenStream {
95 wasmbox_impl(&item.into()).into()
96}
97
98#[proc_macro_attribute]
99pub fn wasmbox_sync(_attr: TokenStream, item: TokenStream) -> TokenStream {
100 wasmbox_sync_impl(&item.into()).into()
101}