af_bevy_plugin_macro/
lib.rs1use convert_case::{Case, Casing};
2use proc_macro::TokenStream;
3use quote::quote;
4use syn::parse::{Parse, ParseStream, Result};
5use syn::{parse_macro_input, Ident, Token};
6struct Input {
7 head: Ident,
8 items: Vec<Ident>,
9}
10impl Parse for Input {
11 fn parse(input: ParseStream) -> Result<Self> {
12 let mut items = Vec::new();
13 let head = input.parse()?;
14 input.parse::<Token![,]>()?;
15 while !input.is_empty() {
16 items.push(input.parse()?);
17 if !input.is_empty() {
18 input.parse::<Token![,]>()?;
19 }
20 }
21 Ok(Input { head, items })
22 }
23}
24
25#[proc_macro]
26pub fn bevy_plugin_group(input: TokenStream) -> TokenStream {
27 let input = parse_macro_input!(input as Input);
28 let snake_items = &input.items;
29 let head = &input.head;
30
31 let plugin_items = snake_items.iter().map(|ident| {
32 Ident::new(
33 &(String::from(&ident.to_string().to_case(Case::Pascal)) + "Plugin"),
34 ident.span(),
35 )
36 });
37
38 let plugin_group_name = Ident::new(
39 &(String::from(head.to_string().to_case(Case::Pascal)) + "Plugins"),
40 head.span(),
41 );
42 TokenStream::from(quote! {
43 #(
44 pub mod #snake_items;
45 pub use #snake_items::*;
46 )*
47
48 pub struct #plugin_group_name;
49 use bevy::{app::PluginGroupBuilder, app::PluginGroup};
50 impl PluginGroup for #plugin_group_name {
51 fn build(self) -> PluginGroupBuilder {
52 PluginGroupBuilder::start::<Self>()
53 #(
54 .add(#snake_items::#plugin_items)
55 )*
56 }
57 }
58
59 })
60}