summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-10-30 05:24:39 +0100
committerHampusM <hampus@hampusmat.com>2026-10-30 05:52:42 +0100
commit723f48d8e008d216978b8ed7d70499c972cc5a1c (patch)
treecdb997249bb0188c35c92c0a68a7c8d91ac222fd
parent5828e00dbe274391a05772380910f82996908b7d (diff)
refactor(engine-ecs): replace uid::WithUid* traits with new component traits
-rw-r--r--engine-ecs-macros/src/lib.rs44
-rw-r--r--engine-ecs/examples/component_events.rs2
-rw-r--r--engine-ecs/examples/component_removed_event.rs2
-rw-r--r--engine-ecs/src/actions.rs13
-rw-r--r--engine-ecs/src/component.rs70
-rw-r--r--engine-ecs/src/lib.rs1
-rw-r--r--engine-ecs/src/pair.rs61
-rw-r--r--engine-ecs/src/phase.rs1
-rw-r--r--engine-ecs/src/query/term.rs113
-rw-r--r--engine-ecs/src/sole.rs34
-rw-r--r--engine-ecs/src/uid.rs45
11 files changed, 223 insertions, 163 deletions
diff --git a/engine-ecs-macros/src/lib.rs b/engine-ecs-macros/src/lib.rs
index 9bc829b..a95cfe4 100644
--- a/engine-ecs-macros/src/lib.rs
+++ b/engine-ecs-macros/src/lib.rs
@@ -45,8 +45,6 @@ pub fn component_derive(input: TokenStream) -> TokenStream
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));
assert!(
@@ -80,14 +78,8 @@ pub fn component_derive(input: TokenStream) -> TokenStream
#id_var
- impl #impl_generics Component for #item_ident #type_generics
- #where_clause
+ impl Component for #item_ident
{
- fn id() -> Uid
- {
- *#id_var_ident
- }
-
fn type_reflection() -> Option<&'static #ecs_path::reflection::Type>
{
struct SpecializationTarget<T>(std::marker::PhantomData<T>);
@@ -134,8 +126,7 @@ pub fn component_derive(input: TokenStream) -> TokenStream
}
}
- impl #impl_generics SystemInput for #item_ident #type_generics
- #where_clause
+ impl SystemInput for #item_ident
{
}
@@ -146,7 +137,18 @@ pub fn component_derive(input: TokenStream) -> TokenStream
#ecs_path::component::Parts::builder()
.name(<Self as Component>::name(&self))
.type_reflection(<Self as Component>::type_reflection())
- .build(<Self as Component>::id(), self)
+ .build(
+ <Self as #ecs_path::component::WithAssociatedId>::id(),
+ self
+ )
+ }
+ }
+
+ impl #ecs_path::component::WithAssociatedId for #item_ident
+ {
+ fn id() -> Uid
+ {
+ *#id_var_ident
}
}
}
@@ -203,11 +205,6 @@ pub fn sole_derive(input: TokenStream) -> TokenStream
impl Sole for #item_ident
{
- fn id() -> Uid
- {
- *#id_var_ident
- }
-
fn type_reflection() -> Option<&'static #ecs_path::reflection::Type>
{
struct SpecializationTarget<T>(std::marker::PhantomData<T>);
@@ -262,7 +259,18 @@ pub fn sole_derive(input: TokenStream) -> TokenStream
.name(<Self as Sole>::name(&self))
.is_sole(true)
.type_reflection(<Self as Sole>::type_reflection())
- .build(<Self as Sole>::id(), self)
+ .build(
+ <Self as #ecs_path::component::WithAssociatedId>::id(),
+ self
+ )
+ }
+ }
+
+ impl #ecs_path::component::WithAssociatedId for #item_ident
+ {
+ fn id() -> Uid
+ {
+ *#id_var_ident
}
}
}
diff --git a/engine-ecs/examples/component_events.rs b/engine-ecs/examples/component_events.rs
index 82d9b6c..b32df8b 100644
--- a/engine-ecs/examples/component_events.rs
+++ b/engine-ecs/examples/component_events.rs
@@ -1,5 +1,5 @@
use engine_ecs::actions::Actions;
-use engine_ecs::component::Component;
+use engine_ecs::component::WithAssociatedId;
use engine_ecs::event::component::{Changed, EventMatchExt, Removed};
use engine_ecs::pair::Pair;
use engine_ecs::phase::UPDATE;
diff --git a/engine-ecs/examples/component_removed_event.rs b/engine-ecs/examples/component_removed_event.rs
index 23dfc92..40d9bc8 100644
--- a/engine-ecs/examples/component_removed_event.rs
+++ b/engine-ecs/examples/component_removed_event.rs
@@ -1,5 +1,5 @@
use engine_ecs::actions::Actions;
-use engine_ecs::component::Component;
+use engine_ecs::component::WithAssociatedId;
use engine_ecs::event::component::{EventMatchExt, Removed};
use engine_ecs::pair::Pair;
use engine_ecs::phase::UPDATE;
diff --git a/engine-ecs/src/actions.rs b/engine-ecs/src/actions.rs
index 69605b3..cef51cc 100644
--- a/engine-ecs/src/actions.rs
+++ b/engine-ecs/src/actions.rs
@@ -1,12 +1,17 @@
use std::borrow::Cow;
use crate::bundle::Bundle;
-use crate::component::{Component, IntoParts, Parts as ComponentParts};
+use crate::component::{
+ Component,
+ IntoParts,
+ Parts as ComponentParts,
+ RemovableTuple as RemovableComponentTuple,
+};
use crate::entity::Name as EntityName;
use crate::event::component::Removed;
use crate::pair::Pair;
use crate::system::{Metadata as SystemMetadata, Param as SystemParam};
-use crate::uid::{Uid, WithUidTuple};
+use crate::uid::Uid;
use crate::{ActionQueue, World};
/// Used to to queue up actions for a [`World`] to perform.
@@ -174,9 +179,9 @@ impl Actions<'_>
}
/// Queues up removing component(s) from a entity at the end of the current tick.
- pub fn remove_comps<Ids: WithUidTuple>(&mut self, entity_uid: Uid)
+ pub fn remove_comps<Components: RemovableComponentTuple>(&mut self, entity_uid: Uid)
{
- self.remove_components(entity_uid, Ids::uids());
+ self.remove_components(entity_uid, Components::ids());
}
/// Queues up setting the target of a entity's pair at the end of the current tick.
diff --git a/engine-ecs/src/component.rs b/engine-ecs/src/component.rs
index 400b12c..d424e16 100644
--- a/engine-ecs/src/component.rs
+++ b/engine-ecs/src/component.rs
@@ -3,6 +3,7 @@ use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use engine_ecs_macros::Component;
+use seq_macro::seq;
use crate::event::component::Changed;
use crate::event::Submitter as EventSubmitter;
@@ -23,13 +24,9 @@ pub mod local;
pub(crate) mod storage;
-pub trait Component: SystemInput + Any + IntoParts
+/// A component that is not a pair and is not a sole.
+pub trait Component: WithAssociatedId + SystemInput + Any + IntoParts
{
- /// Returns the ID of this component.
- fn id() -> Uid
- where
- Self: Sized;
-
fn type_reflection() -> Option<&'static TypeReflection>
where
Self: Sized;
@@ -38,32 +35,50 @@ pub trait Component: SystemInput + Any + IntoParts
fn name(&self) -> &'static str;
}
-impl dyn Component
+pub trait WithAssociatedId
{
- pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real>
- {
- (self as &mut dyn Any).downcast_mut()
- }
+ /// Returns the ID of this component.
+ fn id() -> Uid;
+}
- pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real>
- {
- (self as &dyn Any).downcast_ref()
- }
+/// A component that is removable from it's entity.
+///
+/// This trait is implemented for [`crate::pair::Pair`] so it does not have [`Component`]
+/// as supertrait.
+pub trait Removable: WithAssociatedId {}
- pub fn is<Other: 'static>(&self) -> bool
- {
- (self as &dyn Any).is::<Other>()
- }
-}
+impl<ComponentT: Component> Removable for ComponentT {}
-impl Debug for dyn Component
+/// Implemented by tuples of types implementing [`Removable`].
+///
+/// This trait is sealed so it cannot be implemented by types outside of this module.
+pub trait RemovableTuple: sealed::Sealed
{
- fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
- {
- formatter.debug_struct("Component").finish_non_exhaustive()
- }
+ fn ids() -> impl IntoIterator<Item = Uid>;
+}
+
+macro_rules! gen_removable_tuple_impl {
+ ($c: tt) => {
+ seq!(I in 0..=$c {
+ impl<#(RemovableT~I: Removable,)*> RemovableTuple for (#(RemovableT~I,)*)
+ {
+ fn ids() -> impl IntoIterator<Item = Uid>
+ {
+ [#(RemovableT~I::id(),)*]
+ }
+ }
+
+ impl<#(RemovableT~I: Removable,)*> sealed::Sealed for (#(RemovableT~I,)*)
+ {
+ }
+ });
+ };
}
+seq!(C in 0..=16 {
+ gen_removable_tuple_impl!(C);
+});
+
#[derive(Debug)]
pub struct Handle<'a, DataT: ?Sized + 'static>
{
@@ -394,3 +409,8 @@ pub struct Info
pub name: &'static str,
pub is_sole: bool,
}
+
+mod sealed
+{
+ pub trait Sealed {}
+}
diff --git a/engine-ecs/src/lib.rs b/engine-ecs/src/lib.rs
index a752f6a..6028cf7 100644
--- a/engine-ecs/src/lib.rs
+++ b/engine-ecs/src/lib.rs
@@ -22,6 +22,7 @@ use crate::component::{
Info as ComponentInfo,
IntoParts as IntoComponentParts,
Parts as ComponentParts,
+ WithAssociatedId,
};
use crate::entity::{
Declaration as EntityDeclaration,
diff --git a/engine-ecs/src/pair.rs b/engine-ecs/src/pair.rs
index 834077c..efeead9 100644
--- a/engine-ecs/src/pair.rs
+++ b/engine-ecs/src/pair.rs
@@ -8,6 +8,8 @@ use crate::component::{
HandleMut as ComponentHandleMut,
IntoParts as IntoComponentParts,
Parts as ComponentParts,
+ Removable as RemovableComponent,
+ WithAssociatedId as ComponentWithAssociatedId,
};
use crate::entity::{
Handle as EntityHandle,
@@ -21,7 +23,7 @@ use crate::query::{
TermsBuilderInterface,
};
use crate::reflection::Type as TypeReflection;
-use crate::uid::{PairParams as UidPairParams, Uid, With as WithUid};
+use crate::uid::{PairParams as UidPairParams, Uid};
use crate::util::impl_multiple;
use crate::{Component, EntityComponentRef, World};
@@ -265,7 +267,7 @@ where
_term_metadata: QueryTermMetadata,
)
{
- terms_builder.present([Pair::<Relation, Target>::uid()]);
+ terms_builder.present([Pair::<Relation, Target>::id()]);
}
fn fields(
@@ -276,7 +278,7 @@ where
{
let target_component = search_result
.entity_handle
- .get_matching_components(Pair::<Relation, Target>::uid())
+ .get_matching_components(Pair::<Relation, Target>::id())
.next()
.expect("Not possible");
@@ -308,7 +310,7 @@ where
_term_metadata: QueryTermMetadata,
)
{
- terms_builder.present([Pair::<Relation, Target>::uid()]);
+ terms_builder.present([Pair::<Relation, Target>::id()]);
}
fn fields(
@@ -319,7 +321,7 @@ where
{
let target_component = search_result
.entity_handle
- .get_matching_components(Pair::<Relation, Target>::uid())
+ .get_matching_components(Pair::<Relation, Target>::id())
.next()
.expect("Not possible");
@@ -355,7 +357,7 @@ where
_term_metadata: QueryTermMetadata,
)
{
- terms_builder.present([Self::uid()]);
+ terms_builder.present([Self::id()]);
}
fn fields(
@@ -366,7 +368,7 @@ where
{
let first_matching_comp = search_result
.entity_handle
- .get_matching_components(Self::uid())
+ .get_matching_components(Self::id())
.next()
.expect("Not possible");
@@ -378,12 +380,12 @@ where
}
}
-impl<Relation, Target> WithUid for Pair<Relation, Target>
+impl<Relation, Target> ComponentWithAssociatedId for Pair<Relation, Target>
where
Relation: Component,
Target: Component,
{
- fn uid() -> Uid
+ fn id() -> Uid
{
Uid::new_pair(&UidPairParams {
relation: Relation::id(),
@@ -392,15 +394,28 @@ where
}
}
-impl<Relation> WithUid for Pair<Relation, Wildcard>
+impl<Relation, Target> RemovableComponent for Pair<Relation, Target>
where
Relation: Component,
+ Target: Component,
{
- fn uid() -> Uid
+}
+
+// TODO: Implement RemovableComponent for Pair<Relation, Wildcard>
+// and Pair<Wildcard, Target>.
+//
+// This should only be done after removal of wildcard pairs is added in lib.rs
+
+impl<Relation> Pair<Relation, Wildcard>
+where
+ Relation: Component,
+{
+ #[must_use]
+ pub fn id() -> Uid
{
Uid::new_pair(&UidPairParams {
relation: Relation::id(),
- target: Wildcard::uid(),
+ target: Wildcard::id(),
})
}
}
@@ -464,19 +479,17 @@ impl<'query, Relation, Target> WithWildcard<'query, Relation, Target>
assert!(component_id.is_pair());
assert!(
- Relation::uid() == Wildcard::uid()
+ Relation::uid() == Wildcard::id()
|| component_id.relation() == Relation::uid()
);
assert!(
- Target::uid() == Wildcard::uid() || component_id.target() == Target::uid()
+ Target::uid() == Wildcard::id() || component_id.target() == Target::uid()
);
- assert!(Relation::uid() == Wildcard::uid() || Target::uid() == Wildcard::uid());
+ assert!(Relation::uid() == Wildcard::id() || Target::uid() == Wildcard::id());
- assert!(
- !(Relation::uid() == Wildcard::uid() && Target::uid() == Wildcard::uid())
- );
+ assert!(!(Relation::uid() == Wildcard::id() && Target::uid() == Wildcard::id()));
WithWildcard {
world,
@@ -641,11 +654,9 @@ impl<'query, Relation, Target> MultipleWithWildcard<'query, Relation, Target>
Relation: ComponentOrWildcard,
Target: ComponentOrWildcard,
{
- assert!(Relation::uid() == Wildcard::uid() || Target::uid() == Wildcard::uid());
+ assert!(Relation::uid() == Wildcard::id() || Target::uid() == Wildcard::id());
- assert!(
- !(Relation::uid() == Wildcard::uid() && Target::uid() == Wildcard::uid())
- );
+ assert!(!(Relation::uid() == Wildcard::id() && Target::uid() == Wildcard::id()));
MultipleWithWildcard {
entity_handle,
@@ -691,7 +702,7 @@ impl<'a, Relation: Component> IntoIterator
WithWildcardIter {
inner: self
.entity_handle
- .get_matching_components(Pair::<Relation, Wildcard>::uid()),
+ .get_matching_components(Pair::<Relation, Wildcard>::id()),
world: self.world,
_pd: PhantomData,
}
@@ -736,7 +747,7 @@ pub struct Wildcard(Infallible);
impl Wildcard
{
#[must_use]
- pub fn uid() -> Uid
+ pub fn id() -> Uid
{
Uid::wildcard()
}
@@ -761,7 +772,7 @@ impl ComponentOrWildcard for Wildcard
{
fn uid() -> Uid
{
- Wildcard::uid()
+ Wildcard::id()
}
}
diff --git a/engine-ecs/src/phase.rs b/engine-ecs/src/phase.rs
index 64c1593..e5008ad 100644
--- a/engine-ecs/src/phase.rs
+++ b/engine-ecs/src/phase.rs
@@ -1,3 +1,4 @@
+use crate::component::WithAssociatedId as _;
use crate::{declare_entity, Component, World};
#[cfg(debug_assertions)]
use crate::{
diff --git a/engine-ecs/src/query/term.rs b/engine-ecs/src/query/term.rs
index 980ee87..f5fd531 100644
--- a/engine-ecs/src/query/term.rs
+++ b/engine-ecs/src/query/term.rs
@@ -5,7 +5,9 @@ use crate::component::{
Component,
Handle as ComponentHandle,
HandleMut as ComponentHandleMut,
+ WithAssociatedId as _,
};
+use crate::pair::{Pair, Wildcard};
use crate::query::{
FoundByTraversal,
SearchResult,
@@ -17,19 +19,61 @@ use crate::query::{
Traversal,
TraversalKind,
};
-use crate::uid::With as WithUid;
use crate::World;
-pub struct With<WithUidT>
+pub struct With<T>
+{
+ _pd: PhantomData<T>,
+}
+
+impl<'query, ComponentT: Component> Term<'query> for With<ComponentT>
+{
+ type Fields = ();
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ _term_metadata: TermMetadata,
+ )
+ {
+ terms_builder.present([ComponentT::id()]);
+ }
+
+ fn fields(
+ _world: &'query World,
+ _search_result: &SearchResult<'query, '_>,
+ _term_metadata: TermMetadata,
+ ) -> Self::Fields
+ {
+ }
+}
+
+impl<'query, Relation, Target> Term<'query> for With<Pair<Relation, Target>>
where
- WithUidT: WithUid,
+ Relation: Component,
+ Target: Component,
{
- _pd: PhantomData<WithUidT>,
+ type Fields = ();
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ _term_metadata: TermMetadata,
+ )
+ {
+ terms_builder.present([Pair::<Relation, Target>::id()]);
+ }
+
+ fn fields(
+ _world: &'query World,
+ _search_result: &SearchResult<'query, '_>,
+ _term_metadata: TermMetadata,
+ ) -> Self::Fields
+ {
+ }
}
-impl<'query, WithUidT> Term<'query> for With<WithUidT>
+impl<'query, Relation> Term<'query> for With<Pair<Relation, Wildcard>>
where
- WithUidT: WithUid,
+ Relation: Component,
{
type Fields = ();
@@ -38,7 +82,7 @@ where
_term_metadata: TermMetadata,
)
{
- terms_builder.present([WithUidT::uid()]);
+ terms_builder.present([Pair::<Relation, Wildcard>::id()]);
}
fn fields(
@@ -50,16 +94,59 @@ where
}
}
-pub struct Without<WithUidT>
+pub struct Without<T>
+{
+ _pd: PhantomData<T>,
+}
+
+impl<'query, ComponentT: Component> Term<'query> for Without<ComponentT>
+{
+ type Fields = ();
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ _term_metadata: TermMetadata,
+ )
+ {
+ terms_builder.absent([ComponentT::id()]);
+ }
+
+ fn fields(
+ _world: &'query World,
+ _search_result: &SearchResult<'query, '_>,
+ _term_metadata: TermMetadata,
+ ) -> Self::Fields
+ {
+ }
+}
+
+impl<'query, Relation, Target> Term<'query> for Without<Pair<Relation, Target>>
where
- WithUidT: WithUid,
+ Relation: Component,
+ Target: Component,
{
- _pd: PhantomData<WithUidT>,
+ type Fields = ();
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ _term_metadata: TermMetadata,
+ )
+ {
+ terms_builder.absent([Pair::<Relation, Target>::id()]);
+ }
+
+ fn fields(
+ _world: &'query World,
+ _search_result: &SearchResult<'query, '_>,
+ _term_metadata: TermMetadata,
+ ) -> Self::Fields
+ {
+ }
}
-impl<'query, WithUidT> Term<'query> for Without<WithUidT>
+impl<'query, Relation> Term<'query> for Without<Pair<Relation, Wildcard>>
where
- WithUidT: WithUid,
+ Relation: Component,
{
type Fields = ();
@@ -68,7 +155,7 @@ where
_term_metadata: TermMetadata,
)
{
- terms_builder.absent([WithUidT::uid()]);
+ terms_builder.absent([Pair::<Relation, Wildcard>::id()]);
}
fn fields(
diff --git a/engine-ecs/src/sole.rs b/engine-ecs/src/sole.rs
index 4047b48..9168414 100644
--- a/engine-ecs/src/sole.rs
+++ b/engine-ecs/src/sole.rs
@@ -4,18 +4,14 @@ use std::fmt::Debug;
use crate::component::{
HandleMut as ComponentHandleMut,
IntoParts as IntoComponentParts,
+ WithAssociatedId as ComponentWithAssociatedId,
};
use crate::system::{Metadata as SystemMetadata, Param as SystemParam};
-use crate::uid::Uid;
use crate::World;
/// A component which has a single instance in the [`World`].
-pub trait Sole: Any + IntoComponentParts
+pub trait Sole: Any + IntoComponentParts + ComponentWithAssociatedId
{
- fn id() -> Uid
- where
- Self: Sized;
-
fn type_reflection() -> Option<&'static crate::reflection::Type>
where
Self: Sized;
@@ -24,32 +20,6 @@ pub trait Sole: Any + IntoComponentParts
fn name(&self) -> &'static str;
}
-impl dyn Sole
-{
- pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real>
- {
- (self as &mut dyn Any).downcast_mut()
- }
-
- pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real>
- {
- (self as &dyn Any).downcast_ref()
- }
-
- pub fn is<Other: 'static>(&self) -> bool
- {
- (self as &dyn Any).is::<Other>()
- }
-}
-
-impl Debug for dyn Sole
-{
- fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
- {
- formatter.debug_struct("Sole").finish_non_exhaustive()
- }
-}
-
/// Holds a reference to a singleton component.
#[derive(Debug)]
pub struct Single<'world, SoleT: Sole>
diff --git a/engine-ecs/src/uid.rs b/engine-ecs/src/uid.rs
index 78ca2ad..6b1a4b5 100644
--- a/engine-ecs/src/uid.rs
+++ b/engine-ecs/src/uid.rs
@@ -1,10 +1,7 @@
use std::fmt::{Debug, Display, Formatter};
use std::sync::atomic::{AtomicU32, Ordering};
-use seq_macro::seq;
-
-use crate::component::Component;
-use crate::util::{gen_mask_64, Array, BitMask, NumberExt};
+use crate::util::{gen_mask_64, BitMask, NumberExt};
static NEXT: AtomicU32 = AtomicU32::new(Uid::FIRST_UNIQUE_ID);
@@ -165,43 +162,3 @@ pub struct PairParams
pub relation: Uid,
pub target: Uid,
}
-
-pub trait With: 'static
-{
- fn uid() -> Uid;
-}
-
-impl<ComponentT: Component> With for ComponentT
-{
- fn uid() -> Uid
- {
- Self::id()
- }
-}
-
-pub trait WithUidTuple
-{
- type UidsArray: Array<Uid>;
-
- fn uids() -> Self::UidsArray;
-}
-
-macro_rules! impl_with_uid_tuple {
- ($c: tt) => {
- seq!(I in 0..=$c {
- impl<#(WithUid~I: With,)*> WithUidTuple for (#(WithUid~I,)*)
- {
- type UidsArray = [Uid; $c + 1];
-
- fn uids() -> Self::UidsArray
- {
- [#(WithUid~I::uid(),)*]
- }
- }
- });
- };
-}
-
-seq!(C in 0..=16 {
- impl_with_uid_tuple!(C);
-});