Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

impl EntityBorrow for more types #16917

Merged

Conversation

Victoronz
Copy link
Contributor

@Victoronz Victoronz commented Dec 20, 2024

Objective

Some types like RenderEntity and MainEntity are just wrappers around Entity, so they should be able to implement EntityBorrow/TrustedEntityBorrow. This allows using them with EntitySet functionality.
The EntityRef family are more than direct wrappers around Entity, but can still benefit from being unique in a collection.

Solution

Implement EntityBorrow and TrustedEntityBorrow for simple Entity newtypes and EntityRef types.
These impls are an explicit decision to have the EntityRef types compare like just Entity.
EntityWorldMut is omitted from this impl, because it explicitly contains a &mut World as well, and we do not ever use more than one at a time.

Add EntityBorrow to the bevy_ecs prelude.

Migration Guide

NormalizedWindowRef::entity has been replaced with an EntityBorrow::entity impl.

@Victoronz Victoronz added A-ECS Entities, components, systems, and events D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Needs-Review Needs reviewer attention (from anyone!) to move forward C-Usability A targeted quality-of-life change that makes Bevy easier to use labels Dec 20, 2024
entity: Entity,
location: EntityLocation,
pub(crate) world: UnsafeWorldCell<'w>,
pub(crate) entity: Entity,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really necessary to loosen the privacy here?

It looks like this is only needed so you can get an &Entity instead of an Entity to impl Borrow<Entity> for a few types. Since we're no longer using Borrow<Entity> internally, could we just leave out those impls?

Alternately, could we add a pub (crate) method to get &Entity so that it's clear nothing outside of this module modifies these fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, there is a much simpler solution: I hadn't thought of just adding an entity method on UnsafeEntityCell itself for some reason. Should UnsafeEntityCell itself implement EntityBorrow?

Copy link
Contributor Author

@Victoronz Victoronz Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I remembered why I didn't do this initially. Unless you return &Entity directly from a field, you will get a temporary lifetime error. So unless we increase the visibility here, or move the UnsafeEntityCell type to entity_ref.rs, we cannot impl Borrow<Entity> for the EntityRef types.
The reason why I added this impl is for the original purpose of Borrow: to allow its use in Map and Set types.
But I can omit it instead then.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it works if the method returns a reference to the original value:

impl UnsafeEntityCell<'_> {
    pub(crate) fn entity_ref(&self) -> &Entity {
        &self.entity
    }
}

impl Borrow<Entity> for EntityMut<'_> {
    fn borrow(&self) -> &Entity {
        self.0.entity_ref()
    }
}

But it's a moot point now that you removed them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahhh, you're right! Had I taken my train of thought just a bit further I could've realized, we can just impl Borrow<Entity> and EntityBorrow for UnsafeEntityCell...
I'll add them back.

@@ -869,6 +919,47 @@ impl<'a> TryFrom<&'a mut FilteredEntityMut<'_>> for EntityMut<'a> {
}
}

impl PartialEq for EntityMut<'_> {
fn eq(&self, other: &Self) -> bool {
self.entity() == other.entity()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand why we need to have this, but it's a little amusing since there can't possibly be two EntityMuts alive for the same entity. It's also not very useful with Query::iter_many, since you can never have an EntityMut that would match the query. Well, it can get combined with this other impls as part of the EntityPtr work and then it won't seem odd anymore.

Copy link
Contributor Author

@Victoronz Victoronz Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still can have its entity match another query! That is one thing the nesting_queries() test in entity_set.rs shows. But it is definitely more obscure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I just meant EntityMut specifically. It has write access to all components, so it's going to conflict with any other query that matches the same archetypes. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also meant EntityMut specifically! You can still query for an archetype without accessing any components :)

@@ -386,6 +386,8 @@ impl PartialEq for EntityRef<'_> {

impl Eq for EntityRef<'_> {}

// We intentionally choose to have EntityRef compare like Entity.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the danger here is that entities from different worlds that happen to have the same ID will compare equal. That seems unlikely to be a problem in practice, although it might be worth documenting somewhere.

Copy link
Contributor Author

@Victoronz Victoronz Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it is a bit unfortunate that we can't have both entity comparison/world comparison, but it seems to me that being able to compare them like Entity is a lot more valuable. I think I'll add some documentation to the types themselves.

Copy link
Contributor

@bushrat011899 bushrat011899 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I like seeing gaps in the API filled like this.

@bushrat011899 bushrat011899 added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Dec 22, 2024
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Dec 24, 2024
Merged via the queue into bevyengine:main with commit 5b899dc Dec 24, 2024
29 checks passed
pcwalton pushed a commit to pcwalton/bevy that referenced this pull request Dec 25, 2024
# Objective

Some types like `RenderEntity` and `MainEntity` are just wrappers around
`Entity`, so they should be able to implement
`EntityBorrow`/`TrustedEntityBorrow`. This allows using them with
`EntitySet` functionality.
The `EntityRef` family are more than direct wrappers around `Entity`,
but can still benefit from being unique in a collection.

## Solution

Implement `EntityBorrow` and `TrustedEntityBorrow` for simple `Entity`
newtypes and `EntityRef` types.
These impls are an explicit decision to have the `EntityRef` types
compare like just `Entity`.
`EntityWorldMut` is omitted from this impl, because it explicitly
contains a `&mut World` as well, and we do not ever use more than one at
a time.

Add `EntityBorrow` to the `bevy_ecs` prelude.

## Migration Guide

`NormalizedWindowRef::entity` has been replaced with an
`EntityBorrow::entity` impl.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants