muds_derive/
lib.rs

1//! Implements the `#[derive(Entity)]`, `#[derive(Component)]` macro and `#[storage]` attribute.
2
3#![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/// Derive macro for the `Entity` trait.
19///
20/// ## Examples
21/// ```rust,ignore
22/// use muds::ecs::storage::ArenaStorage;
23///
24/// #[derive(Entity, Debug)]
25/// #[storage(ArenaStorage)] //optional, defaults to `ArenaStorage`
26/// struct E(f32);
27/// ```
28#[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/// Derive macro for the `Component` trait.
58///
59/// ## Examples
60/// ```rust,ignore
61/// use muds::ecs::storage::VecStorage;
62///
63/// #[derive(Component, Debug)]
64/// #[storage(VecStorage)] // optional, defaults to `VecStorage`
65/// struct C(f32);
66/// ```
67#[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}