use std::any::{type_name, Any}; use std::marker::PhantomData; use crate::component::storage::Storage as ComponentStorage; use crate::component::{ is_optional as component_is_optional, Component, FromOptional as ComponentFromOptional, Id as ComponentId, Metadata as ComponentMetadata, }; use crate::entity::Uid as EntityUid; use crate::lock::ReadGuard; use crate::system::{ComponentRefMut, Input as SystemInput}; use crate::type_name::TypeName; use crate::World; #[derive(Debug)] pub struct Relationship { entity_uid: EntityUid, _pd: PhantomData<(Kind, ComponentT)>, } impl Relationship where ComponentT: Component, { pub fn new(entity_uid: EntityUid) -> Self { Self { entity_uid, _pd: PhantomData } } } impl Component for Relationship where Kind: 'static, ComponentT: Component, { type Component = Self; type RefMut<'component> = Relation<'component, Kind, ComponentT>; fn id(&self) -> ComponentId { ComponentId::of::() } fn as_any_mut(&mut self) -> &mut dyn Any { self } fn as_any(&self) -> &dyn Any { self } } impl SystemInput for Relationship where Kind: 'static, ComponentT: Component, { } impl TypeName for Relationship where ComponentT: Component, { fn type_name(&self) -> &'static str { type_name::() } } pub struct Relation<'rel_comp, Kind, ComponentT> where Kind: 'static, ComponentT: Component, { component_storage_lock: ReadGuard<'static, ComponentStorage>, relationship_comp: ComponentRefMut<'rel_comp, Relationship>, } impl<'rel_comp, Kind, ComponentT> ComponentFromOptional<'rel_comp> for Relation<'rel_comp, Kind, ComponentT> where ComponentT: Component, { fn from_optional_component( optional_component: Option< crate::lock::WriteGuard<'rel_comp, Box>, >, world: &'rel_comp World, ) -> Self { let relationship_comp = ComponentRefMut::>::from_optional_component( optional_component, world, ); let component_storage_lock = world .data .component_storage .read_nonblock() .expect("Failed to aquire read-only component storage lock"); Self { relationship_comp, // SAFETY: The component lock is not used for longer than the original // lifetime component_storage_lock: unsafe { component_storage_lock.upgrade_lifetime() }, } } } impl<'rel_comp, Kind, ComponentT> Relation<'rel_comp, Kind, ComponentT> where ComponentT: Component, { /// Retrieves the related-to component. pub fn get(&self) -> Option> { let mut archetype_iter = self.component_storage_lock .find_entities([ComponentMetadata { id: ComponentId::of::(), is_optional: component_is_optional::().into(), }]); let (entity, archetype) = archetype_iter.find_map(|archetype| { let Some(entity) = archetype.get_entity(self.relationship_comp.entity_uid) else { return None; }; Some((entity, archetype)) })?; let component_index = archetype.get_index_for_component(&ComponentId::of::())?; let component = ComponentRefMut::new( entity .get_component(component_index)? .component .write_nonblock() .unwrap_or_else(|_| { panic!( "Failed to aquire read-write lock of component {}", type_name::() ) }), ); Some(component) } /// Changes the related-to entity to the entity with the given UID: pub fn set_entity(&mut self, entity_uid: EntityUid) { self.relationship_comp.entity_uid = entity_uid; } }