use proc_macro::TokenStream;
use quote::quote;
use syn::{ItemFn, Type, parse_macro_input};
mod select_parse;
use select_parse::parse_select;
#[proc_macro_attribute]
pub fn runtime(_args: TokenStream, input: TokenStream) -> TokenStream {
let input_fn = parse_macro_input!(input as ItemFn);
let _fn_name = &input_fn.sig.ident;
let fn_block = &input_fn.block;
let fn_attrs = &input_fn.attrs;
let fn_vis = &input_fn.vis;
let fn_sig = &input_fn.sig;
let expanded = quote! {
#(#fn_attrs)*
#fn_vis #fn_sig {
::gorust::Runtime::init();
let original_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
log::error!("[Goroutine panic] {}", panic_info);
original_hook(panic_info);
}));
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
#fn_block
}));
::gorust::Runtime::wait_for_all();
::gorust::Runtime::shutdown();
match result {
Ok(ret) => ret,
Err(err) => std::panic::resume_unwind(err),
}
}
};
TokenStream::from(expanded)
}
#[proc_macro]
pub fn make_chan(input: TokenStream) -> TokenStream {
let parsed_input = input.to_string();
let parts: Vec<&str> = parsed_input.trim_end_matches(')').split(',').collect();
if parts.len() == 1 {
let ty = parts[0].trim();
let ty_parsed: Type = syn::parse_str(ty).expect("Invalid type in make_chan!");
let expanded = quote! {
::gorust::Channel::<#ty_parsed>::new(0)
};
TokenStream::from(expanded)
} else {
let ty = parts[0].trim();
let ty_parsed: Type = syn::parse_str(ty).expect("Invalid type in make_chan!");
let size = parts[1].trim();
let size_expr: proc_macro2::TokenStream =
size.parse().expect("Invalid capacity in make_chan!");
let expanded = quote! {
::gorust::Channel::<#ty_parsed>::new(#size_expr)
};
TokenStream::from(expanded)
}
}
#[proc_macro]
pub fn select(input: TokenStream) -> TokenStream {
let input_str = input.to_string();
match parse_select(input_str) {
Ok(expanded) => TokenStream::from(expanded),
Err(err) => {
let error = quote! {
compile_error!(#err)
};
TokenStream::from(error)
}
}
}