1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use proc_macro2::{Ident, Span};
5use quote::{quote, quote_spanned};
6use syn::spanned::Spanned;
7use syn::{parse_macro_input, AttributeArgs, DeriveInput, Error, Meta, NestedMeta};
8
9#[proc_macro_attribute]
20pub fn message(args: TokenStream, input: TokenStream) -> TokenStream {
21 let args = parse_macro_input!(args as AttributeArgs);
22 let mut result_type = quote! { () };
23
24 for arg in args {
25 if let NestedMeta::Meta(Meta::NameValue(nv)) = arg {
26 if nv.path.is_ident("result") {
27 if let syn::Lit::Str(lit) = nv.lit {
28 if let Ok(ty) = syn::parse_str::<syn::Type>(&lit.value()) {
29 result_type = quote! { #ty };
30 } else {
31 return Error::new_spanned(&lit, "Expect type")
32 .to_compile_error()
33 .into();
34 }
35 }
36 }
37 }
38 }
39
40 let input = parse_macro_input!(input as DeriveInput);
41 let ident = &input.ident;
42 let expanded = quote! {
43 #input
44 impl xactor::Message for #ident {
45 type Result = #result_type;
46 }
47 };
48 expanded.into()
49}
50
51#[proc_macro_attribute]
55pub fn main(_args: TokenStream, input: TokenStream) -> TokenStream {
56 let mut input = syn::parse_macro_input!(input as syn::ItemFn);
57
58 if &*input.sig.ident.to_string() != "main" {
59 return TokenStream::from(quote_spanned! { input.sig.ident.span() =>
60 compile_error!("only the main function can be tagged with #[xactor::main]"),
61 });
62 }
63
64 if input.sig.asyncness.is_none() {
65 return TokenStream::from(quote_spanned! { input.span() =>
66 compile_error!("the async keyword is missing from the function declaration"),
67 });
68 }
69
70 input.sig.ident = Ident::new("__main", Span::call_site());
71 let ret = &input.sig.output;
72
73 let expanded = quote! {
74 #input
75
76 fn main() #ret {
77 xactor::block_on(__main())
78 }
79 };
80
81 expanded.into()
82}