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

Implement QueryData for &Archetype and EntityLocation #12398

Merged
merged 6 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
159 changes: 156 additions & 3 deletions crates/bevy_ecs/src/query/fetch.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
archetype::Archetype,
archetype::{Archetype, Archetypes},
change_detection::{Ticks, TicksMut},
component::{Component, ComponentId, StorageType, Tick},
entity::Entity,
entity::{Entities, Entity, EntityLocation},
query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
storage::{ComponentSparseSet, Table, TableRow},
world::{
Expand All @@ -18,7 +18,7 @@ use std::{cell::UnsafeCell, marker::PhantomData};
///
/// There are many types that natively implement this trait:
///
/// - **Component references.**
/// - **Component references. (&T and &mut T)**
/// Fetches a component by reference (immutably or mutably).
/// - **`QueryData` tuples.**
/// If every element of a tuple implements `QueryData`, then the tuple itself also implements the same trait.
Expand All @@ -27,6 +27,14 @@ use std::{cell::UnsafeCell, marker::PhantomData};
/// but nesting of tuples allows infinite `WorldQuery`s.
/// - **[`Entity`].**
/// Gets the identifier of the queried entity.
/// - **[`EntityLocation`].**
james7132 marked this conversation as resolved.
Show resolved Hide resolved
/// Gets the location metadata of the queried entity.
/// - **[`EntityRef`].**
/// Read-only access to arbitrary components on the queried entity.
/// - **[`EntityMut`].**
/// Mutable access to arbitrary components on the queried entity.
/// - **[`&Archetype`].**
james7132 marked this conversation as resolved.
Show resolved Hide resolved
/// Read-only access to the archetype-level metadata of the queried entity.
/// - **[`Option`].**
/// By default, a world query only tests entities that have the matching component types.
/// Wrapping it into an `Option` will increase the query search space, and it will return `None` if an entity doesn't satisfy the `WorldQuery`.
Expand Down Expand Up @@ -345,6 +353,76 @@ unsafe impl QueryData for Entity {
/// SAFETY: access is read only
unsafe impl ReadOnlyQueryData for Entity {}

/// SAFETY:
/// `update_component_access` and `update_archetype_component_access` do nothing.
/// This is sound because `fetch` does not access components.
unsafe impl WorldQuery for EntityLocation {
type Item<'w> = EntityLocation;
type Fetch<'w> = &'w Entities;
type State = ();

fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
item
}

unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
_state: &Self::State,
_last_run: Tick,
_this_run: Tick,
) -> Self::Fetch<'w> {
world.entities()
}

const IS_DENSE: bool = true;
james7132 marked this conversation as resolved.
Show resolved Hide resolved

#[inline]
unsafe fn set_archetype<'w>(
_fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
_archetype: &'w Archetype,
_table: &Table,
) {
}

#[inline]
unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
}

#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
_table_row: TableRow,
) -> Self::Item<'w> {
// SAFETY: `fetch` must be called with an entity that exists in the world
unsafe { fetch.get(entity).debug_checked_unwrap() }
}

fn update_component_access(_state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {}

fn init_state(_world: &mut World) {}

fn get_state(_world: &World) -> Option<()> {
Some(())
}

fn matches_component_set(
_state: &Self::State,
_set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
true
}
}

/// SAFETY: `Self` is the same as `Self::ReadOnly`
unsafe impl QueryData for EntityLocation {
type ReadOnly = Self;
}

/// SAFETY: access is read only
unsafe impl ReadOnlyQueryData for EntityLocation {}

/// SAFETY:
/// `fetch` accesses all components in a readonly way.
/// This is sound because `update_component_access` and `update_archetype_component_access` set read access for all components and panic when appropriate.
Expand Down Expand Up @@ -709,6 +787,81 @@ unsafe impl<'a> QueryData for FilteredEntityMut<'a> {
type ReadOnly = FilteredEntityRef<'a>;
}

/// SAFETY:
/// `update_component_access` and `update_archetype_component_access` do nothing.
/// This is sound because `fetch` does not access components.
unsafe impl WorldQuery for &Archetype {
type Item<'w> = &'w Archetype;
type Fetch<'w> = (&'w Entities, &'w Archetypes);
type State = ();

fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
item
}

unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
_state: &Self::State,
_last_run: Tick,
_this_run: Tick,
) -> Self::Fetch<'w> {
(world.entities(), world.archetypes())
}

// This could probably be a non-dense query and just get set a Option<&Archetype> fetch value in
// set_archetypes, but forcing archetypal iteration is likely to be slower in any compound query.
const IS_DENSE: bool = true;

#[inline]
unsafe fn set_archetype<'w>(
_fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
_archetype: &'w Archetype,
_table: &Table,
) {
}

#[inline]
unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
}

#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
_table_row: TableRow,
) -> Self::Item<'w> {
let (entities, archetypes) = *fetch;
// SAFETY: `fetch` must be called with an entity that exists in the world
let location = unsafe { entities.get(entity).debug_checked_unwrap() };
// SAFETY: The assigned archetype for a living entity must always be valid.
unsafe { archetypes.get(location.archetype_id).debug_checked_unwrap() }
}

fn update_component_access(_state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {}

fn init_state(_world: &mut World) {}

fn get_state(_world: &World) -> Option<()> {
Some(())
}

fn matches_component_set(
_state: &Self::State,
_set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
true
}
}

/// SAFETY: `Self` is the same as `Self::ReadOnly`
unsafe impl QueryData for &Archetype {
type ReadOnly = Self;
}

/// SAFETY: access is read only
unsafe impl ReadOnlyQueryData for &Archetype {}

#[doc(hidden)]
pub struct ReadFetch<'w, T> {
// T::STORAGE_TYPE = StorageType::Table
Expand Down
8 changes: 6 additions & 2 deletions crates/bevy_ecs/src/system/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1292,12 +1292,16 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// Besides removing parameters from the query, you can also
/// make limited changes to the types of parameters.
///
/// * Can always add/remove `Entity`
/// * Can always add/remove [`Entity`]
/// * Can always add/remove [`EntityLocation`]
/// * Can always add/remove [`&Archetype`]
/// * `Ref<T>` <-> `&T`
/// * `&mut T` -> `&T`
/// * `&mut T` -> `Ref<T>`
/// * [`EntityMut`](crate::world::EntityMut) -> [`EntityRef`](crate::world::EntityRef)
///
///
/// [`EntityLocation`]: crate::entity::EntityLocation
/// [`&Archetype`]: crate::archetype::Archetype
pub fn transmute_lens<NewD: QueryData>(&mut self) -> QueryLens<'_, NewD> {
self.transmute_lens_filtered::<NewD, ()>()
}
Expand Down
Loading