wasmbox_macro/
lib.rs

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}