use std::any::{type_name, Any}; use std::marker::PhantomData; use std::sync::{Arc, Weak}; 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::{Lock, ReadGuard}; use crate::system::{ComponentRefMut, Input as SystemInput}; use crate::type_name::TypeName; use crate::{World, WorldData}; #[derive(Debug)] pub struct Relationship { entity_uid: EntityUid, component_storage: Weak>, _pd: PhantomData<(Kind, ComponentT)>, } impl Relationship where ComponentT: Component, { pub fn new(world: &World, entity_uid: EntityUid) -> Self { Self { entity_uid, component_storage: Arc::downgrade(&world.data.component_storage), _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 } #[cfg_attr(feature = "debug", tracing::instrument(skip_all))] fn prepare(world_data: &WorldData) where Self: Sized, { let mut component_storage_lock = world_data .component_storage .write_nonblock() .expect("Failed to acquire read-write component storage lock"); #[cfg(feature = "debug")] tracing::debug!( "Adding archetypes lookup entry for component: {}", std::any::type_name::() ); component_storage_lock.add_archetype_lookup_entry([ComponentMetadata { id: ComponentId::of::(), is_optional: component_is_optional::().into(), }]); } } 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>, _component_storage: Arc>, } 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>, >, ) -> Self { let relationship_comp = ComponentRefMut::>::from_optional_component( optional_component, ); let component_storage = relationship_comp .component_storage .upgrade() .expect("World has been dropped"); let component_storage_lock = 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() }, _component_storage: component_storage, } } } 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) } }