Repository: bevyengine/bevy
File: crates/bevy_ecs/src/relationship/mod.rs (Rust)

Code before:
            ..
        }: HookContext,
    ) {
        match relationship_hook_mode {
            RelationshipHookMode::Run => {}
            RelationshipHookMode::Skip => return,
            RelationshipHookMode::RunIfNotLinked => {
                if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
                    return;
                }
            }
        }
        let target_entity = world.entity(entity).get::<Self>().unwrap().get();
        if target_entity == entity {
            warn!(
                "{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.",
                caller.map(|location|format!("{location}: ")).unwrap_or_default(),
                DebugName::type_name::<Self>(),
                DebugName::type_name::<Self>()
            );
            world.commands().entity(entity).remove::<Self>();
            return;
        }
        // For one-to-one relationships, remove existing relationship before adding new one
        let mut current_source_to_remove: Option<Entity> = None;
        if core::any::TypeId::of::<<Self::RelationshipTarget as RelationshipTarget>::Collection>()
            == core::any::TypeId::of::<Entity>()
        {
            if let Ok(target_entity_ref) = world.get_entity(target_entity) {
                if let Some(relationship_target) =
                    target_entity_ref.get::<Self::RelationshipTarget>()
                {
                    // SAFETY: We just checked that the collection type is Entity
                    let entity_collection = unsafe {
                        &*core::ptr::from_ref::<
                            <Self::RelationshipTarget as RelationshipTarget>::Collection,
                        >(relationship_target.collection())
                        .cast::<Entity>()
                    };
                    if *entity_collection != Entity::PLACEHOLDER {
                        current_source_to_remove = Some(*entity_collection);
                    }
                }
            }
        }

        if let Some(current_source) = current_source_to_remove {
            world.commands().entity(current_source).try_remove::<Self>();
        }

        if let Ok(mut entity_commands) = world.commands().get_entity(target_entity) {

Review comment (suggestion):
Checking for a specific type like this feels brittle.  I have no idea whether it's an intended use case, but an external crate could implement `RelationshipSourceCollection` for a wrapper around `Entity`, and would be surprised that the behavior wasn't the same.  

Could we instead express this as a new method on `trait RelationshipSourceCollection`?  I'm not sure what to call it, but something like a `fn source_to_remove_before_add(&mut self) -> Option<Entity>` with a default impl of `None` might work.  

Code after:
            ..
        }: HookContext,
    ) {
        match relationship_hook_mode {
            RelationshipHookMode::Run => {}
            RelationshipHookMode::Skip => return,
            RelationshipHookMode::RunIfNotLinked => {
                if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
                    return;
                }
            }
        }
        let target_entity = world.entity(entity).get::<Self>().unwrap().get();
        if target_entity == entity {
            warn!(
                "{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.",
                caller.map(|location|format!("{location}: ")).unwrap_or_default(),
                DebugName::type_name::<Self>(),
                DebugName::type_name::<Self>()
            );
            world.commands().entity(entity).remove::<Self>();
            return;
        }
        // For one-to-one relationships, remove existing relationship before adding new one
        let current_source_to_remove = world
            .get_entity(target_entity)
            .ok()
            .and_then(|target_entity_ref| target_entity_ref.get::<Self::RelationshipTarget>())
            .and_then(|relationship_target| {
                relationship_target
                    .collection()
                    .source_to_remove_before_add()
            });

        if let Some(current_source) = current_source_to_remove {
            world.commands().entity(current_source).try_remove::<Self>();
        }

        if let Ok(mut entity_commands) = world.commands().get_entity(target_entity) {
            // Deferring is necessary for batch mode
            entity_commands
                .entry::<Self::RelationshipTarget>()
                .and_modify(move |mut relationship_target| {
                    relationship_target.collection_mut_risky().add(entity);
                })
                .or_insert_with(move || {
                    let mut target = Self::RelationshipTarget::with_capacity(1);
                    target.collection_mut_risky().add(entity);
                    target
                });
        } else {