summaryrefslogtreecommitdiff
path: root/ecs-macros
diff options
context:
space:
mode:
Diffstat (limited to 'ecs-macros')
-rw-r--r--ecs-macros/src/lib.rs175
1 files changed, 27 insertions, 148 deletions
diff --git a/ecs-macros/src/lib.rs b/ecs-macros/src/lib.rs
index 862b0b1..7d00736 100644
--- a/ecs-macros/src/lib.rs
+++ b/ecs-macros/src/lib.rs
@@ -1,3 +1,4 @@
+#![deny(clippy::all, clippy::pedantic)]
use std::path::PathBuf as FsPathBuf;
use proc_macro::TokenStream;
@@ -6,7 +7,6 @@ use syn::spanned::Spanned;
use syn::{
parse,
Attribute,
- GenericParam,
Generics,
Ident,
Item,
@@ -14,7 +14,6 @@ use syn::{
ItemStruct,
ItemUnion,
Path,
- Type,
};
use toml::value::{Table as TomlTable, Value as TomlValue};
@@ -42,60 +41,35 @@ macro_rules! syn_path_segment {
};
}
-#[proc_macro_derive(Component, attributes(component))]
+/// Generates a `Component` implementation.
+///
+/// # Panics
+/// Will panic if:
+/// - Not attributed to a type item
+/// - The attributed-to type item is generic
+/// - If parsing the user crate's `Cargo.toml` file fails.
+#[proc_macro_derive(Component)]
pub fn component_derive(input: TokenStream) -> TokenStream
{
let item: TypeItem = parse::<Item>(input).unwrap().try_into().unwrap();
- let ComponentAttribute { handle_type, handle_mut_type } = item
- .attribute::<ComponentAttribute>("component")
- .unwrap_or_default();
-
let item_ident = item.ident();
let (impl_generics, type_generics, where_clause) = item.generics().split_for_impl();
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());
+ assert!(
+ item.generics().params.is_empty(),
+ "Generic types are not supported as components"
+ );
- let id_lut = quote! {
- static #id_lut_ident: LazyLock<Mutex<HashMap<TypeId, Uid>>> =
- LazyLock::new(|| Mutex::new(HashMap::new()));
- };
+ let id_var_ident = format_ident!("{}_ID", item_ident.to_string().to_uppercase());
- 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 id_var = quote! {
+ static #id_var_ident: LazyLock<Uid> = LazyLock::new(|| {
+ Uid::new_unique(UidKind::Component)
});
-
- 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!(
@@ -107,48 +81,26 @@ pub fn component_derive(input: TokenStream) -> TokenStream
mod #mod_ident {
use ::std::any::{Any, TypeId};
use ::std::sync::{LazyLock, Mutex};
- use ::std::collections::HashMap;
use #ecs_path::component::Component;
- use #ecs_path::event::component::{
- Removed as ComponentRemovedEvent,
- Kind as ComponentEventKind,
- };
- use #ecs_path::component::{
- Handle as ComponentHandle,
- HandleMut as ComponentHandleMut
- };
use #ecs_path::uid::{Uid, Kind as UidKind};
use #ecs_path::system::Input as SystemInput;
- use #ecs_path::type_name::TypeName;
use super::*;
- #id_or_ids
+ #id_var
impl #impl_generics Component for #item_ident #type_generics
#where_clause
{
- type Component = Self;
-
- type HandleMut<'component> = #handle_mut_type;
- type Handle<'component> = #handle_type;
-
fn id() -> Uid
{
- #get_id
+ *#id_var_ident
}
- fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid
+ fn name(&self) -> &'static str
{
- match event_kind {
- ComponentEventKind::Removed => ComponentRemovedEvent::<Self>::id(),
- _ => {
- panic!(
- "Support for event kind {event_kind:?} not implemented!"
- );
- }
- }
+ std::any::type_name::<Self>()
}
}
@@ -156,20 +108,16 @@ pub fn component_derive(input: TokenStream) -> TokenStream
#where_clause
{
}
-
- impl #impl_generics TypeName for #item_ident #type_generics
- #where_clause
- {
- fn type_name(&self) -> &'static str
- {
- std::any::type_name::<Self>()
- }
- }
}
}
.into()
}
+/// Generates a `Sole` implementation.
+///
+/// # Panics
+/// Will panic if not attributed to a type item or if parsing the user crate's
+/// `Cargo.toml` file fails.
#[proc_macro_derive(Sole, attributes(sole))]
pub fn sole_derive(input: TokenStream) -> TokenStream
{
@@ -204,15 +152,6 @@ pub fn sole_derive(input: TokenStream) -> TokenStream
self
}
}
-
- impl #impl_generics #ecs_path::type_name::TypeName for #item_ident #type_generics
- #where_clause
- {
- fn type_name(&self) -> &'static str
- {
- std::any::type_name::<Self>()
- }
- }
}
.into()
}
@@ -251,9 +190,7 @@ impl TypeItem
let mut attr: Option<&Attribute> = None;
for item_attr in item_attrs {
- if attr.is_some() {
- panic!("Expected only one {} attribute", attr_ident);
- }
+ assert!(attr.is_none(), "Expected only one {attr_ident} attribute");
if item_attr.path().get_ident()? == attr_ident {
attr = Some(item_attr);
@@ -377,61 +314,3 @@ fn find_engine_ecs_crate_path() -> Option<Path>
None
})
}
-
-#[derive(Debug)]
-struct ComponentAttribute
-{
- handle_type: proc_macro2::TokenStream,
- handle_mut_type: proc_macro2::TokenStream,
-}
-
-impl FromAttribute for ComponentAttribute
-{
- fn from_attribute(attribute: &Attribute) -> Result<Self, syn::Error>
- {
- let mut handle_type: Option<Type> = None;
- let mut handle_mut_type: Option<Type> = None;
-
- attribute.parse_nested_meta(|meta| {
- let Some(flag) = meta.path.get_ident() else {
- return Err(meta.error("Not a single identifier"));
- };
-
- if flag == "handle_type" {
- let value = meta.value()?;
-
- handle_type = Some(value.parse::<Type>()?);
-
- return Ok(());
- } else if flag == "handle_mut_type" {
- let value = meta.value()?;
-
- handle_mut_type = Some(value.parse::<Type>()?);
-
- return Ok(());
- }
-
- Err(meta.error("Unrecognized token"))
- })?;
-
- Ok(Self {
- handle_type: handle_type
- .map(|handle_type| handle_type.into_token_stream())
- .unwrap_or_else(|| Self::default().handle_type),
- handle_mut_type: handle_mut_type
- .map(|handle_mut_type| handle_mut_type.into_token_stream())
- .unwrap_or_else(|| Self::default().handle_mut_type),
- })
- }
-}
-
-impl Default for ComponentAttribute
-{
- fn default() -> Self
- {
- Self {
- handle_type: quote! { ComponentHandle<'component, Self> },
- handle_mut_type: quote! { ComponentHandleMut<'component, Self> },
- }
- }
-}