use proc_macro::TokenStream; use quote::{quote, ToTokens}; use syn::spanned::Spanned; use syn::{parse, Ident, Item, ItemEnum, ItemStruct, ItemUnion}; #[proc_macro_derive(Component)] pub fn component_derive(input: TokenStream) -> TokenStream { let item: TypeItem = parse::(input).unwrap().try_into().unwrap(); let item_ident = item.ident(); quote! { impl ecs::component::Component for #item_ident { fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self } fn as_any(&self) -> &dyn std::any::Any { self } } impl ecs::system::Input for #item_ident {} impl ecs::type_name::TypeName for #item_ident { fn type_name(&self) -> &'static str { std::any::type_name::() } } } .into() } enum TypeItem { Struct(ItemStruct), Enum(ItemEnum), Union(ItemUnion), } impl TypeItem { fn ident(&self) -> &Ident { match self { Self::Struct(struct_item) => &struct_item.ident, Self::Enum(enum_item) => &enum_item.ident, Self::Union(union_item) => &union_item.ident, } } } impl TryFrom for TypeItem { type Error = syn::Error; fn try_from(item: Item) -> Result { match item { Item::Struct(struct_item) => Ok(Self::Struct(struct_item)), Item::Enum(enum_item) => Ok(Self::Enum(enum_item)), Item::Union(union_item) => Ok(Self::Union(union_item)), _ => Err(syn::Error::new( item.span(), "Expected a struct, a enum or a union", )), } } } impl ToTokens for TypeItem { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { match self { Self::Struct(struct_item) => struct_item.to_tokens(tokens), Self::Enum(enum_item) => enum_item.to_tokens(tokens), Self::Union(union_item) => union_item.to_tokens(tokens), } } }