1extern crate proc_macro;
2extern crate quote;
3extern crate syn;
4
5use proc_macro::TokenStream;
6use quote::quote;
7use syn::parse_macro_input;
8
9#[proc_macro_derive(Component)]
10pub fn component(input: TokenStream) -> TokenStream {
11 let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
13
14 let name = &ast.ident;
16 let generated: TokenStream = quote! {
17 impl Component for #name {}
18 }
19 .into();
20
21 generated.into()
23}
24#[proc_macro]
25pub fn generate_component_tuple_impls(input: TokenStream) -> TokenStream {
26 let max_size: usize = parse_macro_input!(input as syn::LitInt)
27 .base10_parse()
28 .expect("Failed to parse integer literal");
29
30 let mut impls = Vec::new();
31
32 for i in 0..=max_size {
33 let type_params: Vec<_> = (0..i).map(|j| quote::format_ident!("T{}", j)).collect();
34 let type_constraints = type_params
35 .iter()
36 .map(|t| quote! { #t: Component + 'static });
37
38 let tuple_type = match type_params.len() {
39 0 => quote! { () },
40 1 => {
41 let param = &type_params[0];
42 quote! { #param }
43 }
44 _ => quote! { (#(#type_params),*) }
45 };
46
47 let type_ids_impl = if type_params.is_empty() {
48 quote! {
49 fn type_ids() -> Vec<TypeId> {
50 vec![]
51 }
52 }
53 } else {
54 let type_ids = type_params.iter().map(|t| {
55 quote! { TypeId::of::<#t>() }
56 });
57 quote! {
58 fn type_ids() -> Vec<TypeId> {
59 vec![#(#type_ids),*]
60 }
61 }
62 };
63
64 impls.push(quote! {
65 impl<#(#type_constraints),*> SystemData for #tuple_type {
66 #type_ids_impl
67 }
68 });
69 }
70
71 quote! {
72 #(#impls)*
73 }
74 .into()
75}