From bfcb849fdf37412e0c61fd0b6f843caa6c4668a9 Mon Sep 17 00:00:00 2001 From: HampusM Date: Mon, 11 Nov 2024 00:12:44 +0100 Subject: feat(ecs-macros): add support for new component IDs --- ecs-macros/src/lib.rs | 123 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 29 deletions(-) diff --git a/ecs-macros/src/lib.rs b/ecs-macros/src/lib.rs index bc2d5ed..8bfce38 100644 --- a/ecs-macros/src/lib.rs +++ b/ecs-macros/src/lib.rs @@ -1,12 +1,12 @@ -use std::env; use std::path::PathBuf as FsPathBuf; use proc_macro::TokenStream; -use quote::{quote, ToTokens}; +use quote::{format_ident, quote, ToTokens}; use syn::spanned::Spanned; use syn::{ parse, Attribute, + GenericParam, Generics, Ident, Item, @@ -52,45 +52,110 @@ pub fn component_derive(input: TokenStream) -> TokenStream let ecs_path = find_engine_ecs_crate_path().unwrap_or_else(|| syn_path!(ecs)); + let (id_or_ids, get_id) = if !item.generics().params.is_empty() { + let id_lut_ident = + format_ident!("{}_ID_LUT", item_ident.to_string().to_uppercase()); + + let id_lut = quote! { + static #id_lut_ident: LazyLock>> = + LazyLock::new(|| Mutex::new(HashMap::new())); + }; + + let generics = item.generics().params.iter().map(|param| match param { + GenericParam::Type(type_param) => type_param.ident.clone(), + GenericParam::Lifetime(_) => panic!("Lifetime generics are not supported"), + GenericParam::Const(_) => panic!("Const generics are not supported"), + }); + + let get_id = quote! { + *#id_lut_ident + .try_lock() + .unwrap() + .entry(TypeId::of::<(#(#generics,)*)>()) + .or_insert_with(|| Uid::new_unique(UidKind::Component)) + }; + + (id_lut, get_id) + } else { + let id_lazylock_ident = + format_ident!("{}_ID", item_ident.to_string().to_uppercase()); + + let id_lazylock = quote! { + static #id_lazylock_ident: LazyLock = LazyLock::new(|| { + Uid::new_unique(UidKind::Component) + }); + }; + + let get_id = quote! { + *#id_lazylock_ident + }; + + (id_lazylock, get_id) + }; + + let mod_ident = format_ident!( + "__ecs_priv_component_impl_{}", + item_ident.to_string().to_lowercase() + ); + quote! { - impl #impl_generics #ecs_path::component::Component for #item_ident #type_generics - #where_clause - { - type Component = Self; + mod #mod_ident { + use ::std::any::{Any, TypeId}; + use ::std::sync::{LazyLock, Mutex}; + use ::std::collections::HashMap; - type RefMut<'component> = - #ecs_path::system::ComponentRefMut<'component, Self>; + use #ecs_path::component::Component; + use #ecs_path::system::ComponentRefMut; + use #ecs_path::system::ComponentRef; + use #ecs_path::uid::{Uid, Kind as UidKind}; + use #ecs_path::system::Input as SystemInput; + use #ecs_path::type_name::TypeName; - type Ref<'component> = - #ecs_path::system::ComponentRef<'component, Self>; + use super::*; - fn id(&self) -> #ecs_path::component::Id - { - #ecs_path::component::Id::of::() - } + #id_or_ids - fn as_any_mut(&mut self) -> &mut dyn std::any::Any + impl #impl_generics Component for #item_ident #type_generics + #where_clause { - self + type Component = Self; + + type RefMut<'component> = ComponentRefMut<'component, Self>; + type Ref<'component> = ComponentRef<'component, Self>; + + fn id() -> Uid + { + #get_id + } + + fn self_id(&self) -> Uid + { + Self::id() + } + + fn as_any_mut(&mut self) -> &mut dyn Any + { + self + } + + fn as_any(&self) -> &dyn Any + { + self + } } - fn as_any(&self) -> &dyn std::any::Any + impl #impl_generics SystemInput for #item_ident #type_generics + #where_clause { - self } - } - impl #impl_generics #ecs_path::system::Input for #item_ident #type_generics - #where_clause - { - } - - impl #impl_generics #ecs_path::type_name::TypeName for #item_ident #type_generics - #where_clause - { - fn type_name(&self) -> &'static str + impl #impl_generics TypeName for #item_ident #type_generics + #where_clause { - std::any::type_name::() + fn type_name(&self) -> &'static str + { + std::any::type_name::() + } } } } -- cgit v1.2.3-18-g5258