summaryrefslogtreecommitdiff
path: root/ecs-macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'ecs-macros/src')
-rw-r--r--ecs-macros/src/lib.rs123
1 files 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<Mutex<HashMap<TypeId, Uid>>> =
+ 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<Uid> = 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::<Self>()
- }
+ #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::<Self>()
+ fn type_name(&self) -> &'static str
+ {
+ std::any::type_name::<Self>()
+ }
}
}
}