diff options
Diffstat (limited to 'ecs/src/entity.rs')
| -rw-r--r-- | ecs/src/entity.rs | 209 |
1 files changed, 172 insertions, 37 deletions
diff --git a/ecs/src/entity.rs b/ecs/src/entity.rs index 562f7ea..ad9f179 100644 --- a/ecs/src/entity.rs +++ b/ecs/src/entity.rs @@ -1,6 +1,6 @@ use std::any::type_name; - -use linkme::distributed_slice; +use std::ops::Deref; +use std::sync::LazyLock; use crate::component::storage::archetype::{ Archetype, @@ -10,19 +10,26 @@ use crate::component::storage::archetype::{ use crate::component::{ Component, Handle as ComponentHandle, - HandleFromEntityComponentRef, HandleMut as ComponentHandleMut, }; +use crate::pair::{ + ComponentOrWildcard, + MultipleWithWildcard as PairMultipleWithWildcard, + Pair, + WithWildcard as PairWithWildcard, +}; use crate::uid::{Kind as UidKind, Uid}; use crate::{EntityComponentRef, World}; +pub mod obtainer; + /// A handle to a entity. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Handle<'a> { - world: &'a World, archetype: &'a Archetype, entity: &'a ArchetypeEntity, + world: &'a World, } impl<'a> Handle<'a> @@ -43,20 +50,21 @@ impl<'a> Handle<'a> /// - The component's ID is not a component ID /// - The component is mutably borrowed elsewhere #[must_use] - pub fn get<ComponentT: Component>(&self) -> Option<ComponentHandle<'_, ComponentT>> + pub fn get<ComponentT: Component>(&self) -> Option<ComponentHandle<'a, ComponentT>> { assert_eq!(ComponentT::id().kind(), UidKind::Component); let component = self.get_matching_components(ComponentT::id()).next()?; Some( - ComponentHandle::from_entity_component_ref(Some(component), self.world) - .unwrap_or_else(|err| { + ComponentHandle::from_entity_component_ref(&component).unwrap_or_else( + |err| { panic!( - "Taking component {} lock failed: {err}", + "Creating handle to component {} failed: {err}", type_name::<ComponentT>() ); - }), + }, + ), ) } @@ -70,23 +78,118 @@ impl<'a> Handle<'a> #[must_use] pub fn get_mut<ComponentT: Component>( &self, - ) -> Option<ComponentHandleMut<'_, ComponentT>> + ) -> Option<ComponentHandleMut<'a, ComponentT>> { assert_eq!(ComponentT::id().kind(), UidKind::Component); let component = self.get_matching_components(ComponentT::id()).next()?; Some( - ComponentHandleMut::from_entity_component_ref(Some(component), self.world) + ComponentHandleMut::from_entity_component_ref(&component, self.world) .unwrap_or_else(|err| { panic!( - "Taking component {} lock failed: {err}", + "Creating handle to component {} failed: {err}", type_name::<ComponentT>() ); }), ) } + /// Returns a reference to the component with the ID `id` in this entity. + /// `None` is returned if the component isn't found. + /// + /// # Panics + /// Will panic if: + /// - The ID is not a component/pair ID + /// - The component is borrowed mutably elsewhere + /// - The component type is incorrect + #[must_use] + pub fn get_with_id<ComponentDataT: 'static>( + &self, + id: Uid, + ) -> Option<ComponentHandle<'a, ComponentDataT>> + { + assert!( + matches!(id.kind(), UidKind::Component | UidKind::Pair), + "ID {id:?} is not a component/pair ID" + ); + + let component = self.get_matching_components(id).next()?; + + Some( + ComponentHandle::from_entity_component_ref(&component).unwrap_or_else( + |err| { + panic!( + "Creating handle to component {} failed: {err}", + type_name::<ComponentDataT>() + ); + }, + ), + ) + } + + /// Returns a mutable reference to the component with the ID `id` in this entity. + /// `None` is returned if the component isn't found. + /// + /// # Panics + /// Will panic if: + /// - The ID is not a component/pair ID + /// - The component is borrowed elsewhere + /// - The component type is incorrect + #[must_use] + pub fn get_with_id_mut<ComponentDataT: 'static>( + &self, + id: Uid, + ) -> Option<ComponentHandleMut<'a, ComponentDataT>> + { + assert!( + matches!(id.kind(), UidKind::Component | UidKind::Pair), + "ID {id:?} is not a component/pair ID" + ); + + let component = self.get_matching_components(id).next()?; + + Some( + ComponentHandleMut::from_entity_component_ref(&component, self.world) + .unwrap_or_else(|err| { + panic!( + "Creating handle to component {} failed: {err}", + type_name::<ComponentDataT>() + ); + }), + ) + } + + #[must_use] + pub fn get_first_wildcard_pair_match<Relation, Target>( + &self, + ) -> Option<PairWithWildcard<'a, Relation, Target>> + where + Relation: ComponentOrWildcard, + Target: ComponentOrWildcard, + { + let mut matching_comps = self.get_matching_components( + Pair::builder() + .relation_id(Relation::uid()) + .target_id(Target::uid()) + .build() + .id(), + ); + + Some(PairWithWildcard::new(self.world, matching_comps.next()?)) + } + + #[must_use] + pub fn get_wildcard_pair_matches<Relation, Target>( + &self, + ) -> PairMultipleWithWildcard<'a, Relation, Target> + where + Relation: ComponentOrWildcard, + Target: ComponentOrWildcard, + { + PairMultipleWithWildcard::new(self.world, self.clone()) + } + #[inline] #[must_use] pub fn get_matching_components(&self, component_uid: Uid) @@ -98,13 +201,27 @@ impl<'a> Handle<'a> } } + /// Returns whether or not this entity contains a component with the specified `Uid`. + #[must_use] + pub fn has_component(&self, component_uid: Uid) -> bool + { + self.archetype + .contains_component_with_exact_id(component_uid) + } + + /// Returns the `Uids`s of the components this entity has. + pub fn component_ids(&self) -> impl Iterator<Item = Uid> + '_ + { + self.archetype.component_ids_sorted() + } + pub(crate) fn new( - world: &'a World, archetype: &'a Archetype, entity: &'a ArchetypeEntity, + world: &'a World, ) -> Self { - Self { world, archetype, entity } + Self { archetype, entity, world } } } @@ -126,35 +243,53 @@ impl<'a> Iterator for MatchingComponentIter<'a> Some(EntityComponentRef::new( matching_component_id, self.entity.components().get(index).unwrap(), + self.entity.uid(), )) } } +/// The data type of a declaration of a entity. +#[derive(Debug)] +pub struct Declaration +{ + uid: LazyLock<Uid>, + create_func: fn(&mut World), +} + +impl Declaration +{ + pub(crate) fn create(&self, world: &mut World) + { + (self.create_func)(world); + } + + #[doc(hidden)] + pub const fn new(create_func: fn(&mut World)) -> Self + { + Self { + uid: LazyLock::new(|| Uid::new_unique(UidKind::Entity)), + create_func, + } + } +} + +impl Deref for Declaration +{ + type Target = Uid; + + fn deref(&self) -> &Self::Target + { + &self.uid + } +} + #[allow(clippy::module_name_repetitions)] #[macro_export] -macro_rules! static_entity { +macro_rules! declare_entity { ($visibility: vis $ident: ident, $components: expr) => { - $visibility static $ident: ::std::sync::LazyLock<$crate::uid::Uid> = - ::std::sync::LazyLock::new(|| { - $crate::uid::Uid::new_unique($crate::uid::Kind::Entity) + $visibility static $ident: $crate::entity::Declaration = + $crate::entity::Declaration::new(|world| { + world.create_entity_with_uid(*$ident, $components); }); - - $crate::private::paste::paste! { - mod [<__ecs_ $ident:lower _static_entity_priv>] { - use super::*; - - #[$crate::private::linkme::distributed_slice( - $crate::entity::CREATE_STATIC_ENTITIES - )] - #[linkme(crate=$crate::private::linkme)] - static CREATE_STATIC_ENTITY: fn(&mut $crate::World) = |world| { - world.create_entity_with_uid($components, *$ident); - }; - } - } } } - -#[distributed_slice] -#[doc(hidden)] -pub static CREATE_STATIC_ENTITIES: [fn(&mut World)]; |
