#![feature(extend_one, let_chains, anonymous_lifetime_in_impl_trait, extract_if)]
use std::collections::HashMap;
use proc_macro::TokenStream;
use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::{spanned::Spanned, ItemEnum, Path, TraitItemFn, parse_macro_input};
use crate::{feature_gates::FeatureGates, util::generate_gate};
mod enums;
mod feature_gates;
mod generics;
mod handle;
mod plugin_interface;
mod util;
#[proc_macro_attribute]
pub fn io_plugin(attribute_data: TokenStream, input: TokenStream) -> TokenStream {
let gates = syn::parse::<FeatureGates>(attribute_data).ok();
let gates = gates.map(|g| g.hashmap()).unwrap_or(HashMap::new());
let mut input = parse_macro_input!(input as ItemEnum);
if let Some(lifetime) = input.generics.lifetimes().last() {
return quote_spanned!(lifetime.span()=>compile_error!("lifetimes are not supported in `io_plugin`");).into();
}
input.ident = format_ident!("{}", input.ident.to_string().trim_start_matches("_"));
let (message, response, response_impl) = enums::split_enum(&mut input);
for ty in input.generics.type_params_mut() {
ty.default = None;
}
#[allow(unused_variables)]
let handle = handle::generate_handle(
input.clone(),
message.clone(),
response.clone(),
generate_gate(gates.get("handle")),
);
let gate = gates.get("plugin_trait");
let (plugin_trait, main_loop_iteration) =
plugin_interface::generate_trait(input.clone(), message.clone(), response.clone(), gate);
let plugin_trait_gate = generate_gate(gate);
quote_spanned!(message.span()=>
#message
#response
#response_impl
#plugin_trait_gate
#plugin_trait
#plugin_trait_gate
#main_loop_iteration
#handle
)
.into()
}
#[proc_macro_attribute]
pub fn handle_doc(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
#[proc_macro_attribute]
pub fn plugin_trait_doc(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
#[proc_macro_attribute]
pub fn message_attributes(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
#[proc_macro_attribute]
pub fn response_attributes(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
#[proc_macro_attribute]
pub fn trait_method_default(attr: TokenStream, item: TokenStream) -> TokenStream {
let mut method = parse_macro_input!(item as TraitItemFn);
let signature = &method.sig;
let args = signature.inputs.iter().filter_map(|arg| {
if let syn::FnArg::Typed(arg) = arg {
Some(arg.pat.to_token_stream())
} else {
None
}
});
let implementation = parse_macro_input!(attr as Path);
method.semi_token = None;
quote!(#signature {
async move {
#implementation(self, #(#args),*).await
}
})
.into()
}