1#![recursion_limit = "128"]
4
5extern crate proc_macro;
6extern crate proc_macro2;
7#[macro_use]
8extern crate quote;
9#[macro_use]
10extern crate syn;
11
12use proc_macro::TokenStream;
13use syn::{
14 parse::{Parse, ParseStream, Result},
15 DeriveInput, Path,
16};
17
18#[proc_macro_derive(Entity, attributes(storage))]
29pub fn entity(input: TokenStream) -> TokenStream {
30 let ast = syn::parse(input).unwrap();
31 let gen = impl_entity(&ast);
32 gen.into()
33}
34
35fn impl_entity(ast: &DeriveInput) -> proc_macro2::TokenStream {
36 let name = &ast.ident;
37 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
38
39 let storage = ast
40 .attrs
41 .iter()
42 .find(|attr| attr.path.segments[0].ident == "storage")
43 .map(|attr| {
44 syn::parse2::<StorageAttribute>(attr.tokens.clone())
45 .unwrap()
46 .storage
47 })
48 .unwrap_or_else(|| parse_quote!(muds::ecs::storage::ArenaStorage));
49
50 quote! {
51 impl #impl_generics muds::ecs::Entity for #name #ty_generics #where_clause {
52 type Storage = #storage<Self>;
53 }
54 }
55}
56
57#[proc_macro_derive(Component, attributes(storage))]
68pub fn component(input: TokenStream) -> TokenStream {
69 let ast = syn::parse(input).unwrap();
70 let gen = impl_component(&ast);
71 gen.into()
72}
73
74fn impl_component(ast: &DeriveInput) -> proc_macro2::TokenStream {
75 let name = &ast.ident;
76 let (_, ty_generics, where_clause) = ast.generics.split_for_impl();
77 let type_params = ast.generics.type_params();
78
79 let storage = ast
80 .attrs
81 .iter()
82 .find(|attr| attr.path.segments[0].ident == "storage")
83 .map(|attr| {
84 syn::parse2::<StorageAttribute>(attr.tokens.clone())
85 .unwrap()
86 .storage
87 })
88 .unwrap_or_else(|| parse_quote!(muds::ecs::storage::VecStorage));
89
90 quote! {
91 impl <Entity: muds::ecs::Entity + 'static, #(#type_params),*> muds::ecs::Component<Entity> for #name #ty_generics #where_clause {
92 type Storage = #storage<Entity, Self>;
93 }
94 }
95}
96
97struct StorageAttribute {
98 storage: Path,
99}
100
101impl Parse for StorageAttribute {
102 fn parse(input: ParseStream) -> Result<Self> {
103 let content;
104 let _parenthesized_token = parenthesized!(content in input);
105
106 Ok(StorageAttribute {
107 storage: content.parse()?,
108 })
109 }
110}