1#![feature(extend_one, let_chains, anonymous_lifetime_in_impl_trait, extract_if)]
2
3use std::collections::HashMap;
4
5use proc_macro::TokenStream;
6use quote::{format_ident, quote, quote_spanned, ToTokens};
7use syn::{spanned::Spanned, ItemEnum, Path, TraitItemFn, parse_macro_input};
8
9use crate::{feature_gates::FeatureGates, util::generate_gate};
10
11mod enums;
12mod feature_gates;
13mod generics;
14mod handle;
15mod plugin_interface;
16mod util;
17
18#[proc_macro_attribute]
28pub fn io_plugin(attribute_data: TokenStream, input: TokenStream) -> TokenStream {
29 let gates = syn::parse::<FeatureGates>(attribute_data).ok();
30 let gates = gates.map(|g| g.hashmap()).unwrap_or(HashMap::new());
31 let mut input = parse_macro_input!(input as ItemEnum);
32
33 if let Some(lifetime) = input.generics.lifetimes().last() {
34 return quote_spanned!(lifetime.span()=>compile_error!("lifetimes are not supported in `io_plugin`");).into();
35 }
36
37 input.ident = format_ident!("{}", input.ident.to_string().trim_start_matches("_"));
38
39 let (message, response, response_impl) = enums::split_enum(&mut input);
40
41 for ty in input.generics.type_params_mut() {
42 ty.default = None;
43 }
44
45 #[allow(unused_variables)]
46 let handle = handle::generate_handle(
47 input.clone(),
48 message.clone(),
49 response.clone(),
50 generate_gate(gates.get("handle")),
51 );
52
53 let gate = gates.get("plugin_trait");
54 let (plugin_trait, main_loop_iteration) =
55 plugin_interface::generate_trait(input.clone(), message.clone(), response.clone(), gate);
56 let plugin_trait_gate = generate_gate(gate);
57
58 quote_spanned!(message.span()=>
59 #message
60
61 #response
62 #response_impl
63
64 #plugin_trait_gate
65 #plugin_trait
66
67 #plugin_trait_gate
68 #main_loop_iteration
69
70 #handle
71 )
72 .into()
73}
74
75#[proc_macro_attribute]
77pub fn handle_doc(_attr: TokenStream, item: TokenStream) -> TokenStream {
78 item
79}
80
81#[proc_macro_attribute]
83pub fn plugin_trait_doc(_attr: TokenStream, item: TokenStream) -> TokenStream {
84 item
85}
86
87#[proc_macro_attribute]
89pub fn message_attributes(_attr: TokenStream, item: TokenStream) -> TokenStream {
90 item
91}
92
93#[proc_macro_attribute]
95pub fn response_attributes(_attr: TokenStream, item: TokenStream) -> TokenStream {
96 item
97}
98
99#[proc_macro_attribute]
101pub fn trait_method_default(attr: TokenStream, item: TokenStream) -> TokenStream {
102 let mut method = parse_macro_input!(item as TraitItemFn);
103 let signature = &method.sig;
104 let args = signature.inputs.iter().filter_map(|arg| {
105 if let syn::FnArg::Typed(arg) = arg {
106 Some(arg.pat.to_token_stream())
107 } else {
108 None
109 }
110 });
111 let implementation = parse_macro_input!(attr as Path);
112 method.semi_token = None;
113 quote!(#signature {
114 async move {
115 #implementation(self, #(#args),*).await
116 }
117 })
118 .into()
119}