Skip to content

Combine Query and QueryLens using a type parameter for state #18162

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

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion crates/bevy_ecs/src/query/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
bundle::Bundle,
change_detection::{MaybeLocation, Ticks, TicksMut},
component::{Component, ComponentId, Components, Mutable, StorageType, Tick},
entity::{Entities, Entity, EntityLocation},
entity::{Entities, Entity, EntityEquivalent, EntityLocation},
query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
storage::{ComponentSparseSet, Table, TableRow},
world::{
Expand Down Expand Up @@ -332,6 +332,20 @@ pub unsafe trait QueryData: WorldQuery {
/// This must only be implemented for read-only [`QueryData`]'s.
pub unsafe trait ReadOnlyQueryData: QueryData<ReadOnly = Self> {}

/// A [`QueryData`] type that produces a [`EntityEquivalent`] item
/// equaling the `Entity` it is addressed by.
///
/// # Safety
///
/// [`<Self as QueryData>::fetch`](QueryData::fetch) must always return an item whose `Entity`
/// equals the one the function was called with.
/// I.e.: `Self::fetch(fetch, entity, table_row).entity() == entity` always holds.
pub unsafe trait EntityEquivalentQueryData: QueryData
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think about leaving out the Equivalent from the trait name?
It seems redundant, the bound on Item defines what this trait sees as an entity, and plain EntityQueryData would be easier to parse/understand imo.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you think about leaving out the Equivalent from the trait name? It seems redundant, the bound on Item defines what this trait sees as an entity, and plain EntityQueryData would be easier to parse/understand imo.

I don't have any especially strong opinions here. Most people won't need to look at this trait at all; they'll expect QueryIter<Entity> to be usable as an EntitySet, and it will be, so they won't worry about how that was implemented.

The trickiest part here is that MainEntity and RenderEntity are EntityEquivalent + QueryData, but can't be EntityEquivalentQueryData because they return a different entity. So maybe EntityEquivalentQueryData is misleading on that count? But EntityQueryData seems like it has the same confusion. Maybe something math-y? No, ReflexiveEntityQueryData just sounds awkward.

Since the stakes are low and none of the options seem perfect, I'm inclined to leave it alone for now, but if you argue more then I'll probably change it rather than argue back :).

where
for<'a> Self: QueryData<Item<'a>: EntityEquivalent>,
{
}

/// The item type returned when a [`WorldQuery`] is iterated over
pub type QueryItem<'w, Q> = <Q as QueryData>::Item<'w>;
/// The read-only variant of the item type returned when a [`QueryData`] is iterated over immutably
Expand Down Expand Up @@ -409,6 +423,9 @@ unsafe impl QueryData for Entity {
/// SAFETY: access is read only
unsafe impl ReadOnlyQueryData for Entity {}

/// SAFETY: `entity()` returns `self`, and `fetch` returns `entity`
unsafe impl EntityEquivalentQueryData for Entity {}

/// SAFETY:
/// `update_component_access` and `update_archetype_component_access` do nothing.
/// This is sound because `fetch` does not access components.
Expand Down Expand Up @@ -570,6 +587,9 @@ unsafe impl<'a> QueryData for EntityRef<'a> {
/// SAFETY: access is read only
unsafe impl ReadOnlyQueryData for EntityRef<'_> {}

/// SAFETY: `entity()` returns the `entity` used to get the `UnsafeEntityCell`, and `fetch` constructs that from `entity`
unsafe impl EntityEquivalentQueryData for EntityRef<'_> {}

/// SAFETY: The accesses of `Self::ReadOnly` are a subset of the accesses of `Self`
unsafe impl<'a> WorldQuery for EntityMut<'a> {
type Fetch<'w> = UnsafeWorldCell<'w>;
Expand Down Expand Up @@ -648,6 +668,9 @@ unsafe impl<'a> QueryData for EntityMut<'a> {
}
}

/// SAFETY: `entity()` returns the `entity` used to get the `UnsafeEntityCell`, and `fetch` constructs that from `entity`
unsafe impl EntityEquivalentQueryData for EntityMut<'_> {}

/// SAFETY: The accesses of `Self::ReadOnly` are a subset of the accesses of `Self`
unsafe impl<'a> WorldQuery for FilteredEntityRef<'a> {
type Fetch<'w> = (UnsafeWorldCell<'w>, Access<ComponentId>);
Expand Down Expand Up @@ -757,6 +780,9 @@ unsafe impl<'a> QueryData for FilteredEntityRef<'a> {
/// SAFETY: Access is read-only.
unsafe impl ReadOnlyQueryData for FilteredEntityRef<'_> {}

/// SAFETY: `entity()` returns the `entity` used to get the `UnsafeEntityCell`, and `fetch` constructs that from `entity`
unsafe impl EntityEquivalentQueryData for FilteredEntityRef<'_> {}

/// SAFETY: The accesses of `Self::ReadOnly` are a subset of the accesses of `Self`
unsafe impl<'a> WorldQuery for FilteredEntityMut<'a> {
type Fetch<'w> = (UnsafeWorldCell<'w>, Access<ComponentId>);
Expand Down Expand Up @@ -861,6 +887,9 @@ unsafe impl<'a> QueryData for FilteredEntityMut<'a> {
}
}

/// SAFETY: `entity()` returns the `entity` used to get the `UnsafeEntityCell`, and `fetch` constructs that from `entity`
unsafe impl EntityEquivalentQueryData for FilteredEntityMut<'_> {}

/// SAFETY: `EntityRefExcept` guards access to all components in the bundle `B`
/// and populates `Access` values so that queries that conflict with this access
/// are rejected.
Expand Down Expand Up @@ -961,6 +990,9 @@ where
/// components.
unsafe impl<'a, B> ReadOnlyQueryData for EntityRefExcept<'a, B> where B: Bundle {}

/// SAFETY: `entity()` returns the `entity` used to get the `UnsafeEntityCell`, and `fetch` constructs that from `entity`
unsafe impl<B: Bundle> EntityEquivalentQueryData for EntityRefExcept<'_, B> {}

/// SAFETY: `EntityMutExcept` guards access to all components in the bundle `B`
/// and populates `Access` values so that queries that conflict with this access
/// are rejected.
Expand Down Expand Up @@ -1058,6 +1090,9 @@ where
}
}

/// SAFETY: `entity()` returns the `entity` used to get the `UnsafeEntityCell`, and `fetch` constructs that from `entity`
unsafe impl<B: Bundle> EntityEquivalentQueryData for EntityMutExcept<'_, B> {}

/// SAFETY:
/// `update_component_access` and `update_archetype_component_access` do nothing.
/// This is sound because `fetch` does not access components.
Expand Down
Loading