diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 99ec1cb98e250..b8e45f714bd3c 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -2666,31 +2666,184 @@ impl<'__w, T: Component> ContiguousQueryData for Mut<'__w, /// /// # Example /// +/// The simplest way to use a `NestedQuery` is with a `#[derive(QueryData)]` struct. +/// The `Query` will be available on the generated `Item` struct, +/// and we can use the query in methods on that struct. +/// /// ``` /// # use bevy_ecs::prelude::*; -/// # use bevy_ecs::query::{QueryData, NestedQuery}; +/// # use bevy_ecs::query::{NestedQuery, QueryData, QueryFilter, ReadOnlyQueryData}; /// # -/// #[derive(Component)] -/// struct A(Entity); +/// # #[derive(Component)] +/// # struct Data(usize); +/// # +/// # let mut world = World::new(); +/// # +/// // We want to create a relational query data +/// // that lets us query components on an entity's parent, +/// // like this: +/// let root = world.spawn(Data(3)).id(); +/// let child = world.spawn(ChildOf(root)).id(); /// -/// #[derive(Component)] -/// struct Name(String); +/// let mut query = world.query::>(); +/// let &Data(data) = query.query(&mut world).get(child).unwrap().data().unwrap(); +/// assert_eq!(data, 3); /// +/// // We derive a query data struct that contains the relation plus a `NestedQuery` /// #[derive(QueryData)] -/// struct NameFromA { -/// a: &'static A, -/// query: NestedQuery<&'static Name>, +/// struct Parent { +/// // This will query `ChildOf` on the entity itself, +/// // so we can find the parent entity +/// parent: &'static ChildOf, +/// // This will provide a `Query` that we can use to +/// // query data on the parent entity +/// nested_query: NestedQuery, +/// } +/// +/// // And add a method on the generated item struct to invoke the nested query. +/// impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ParentItem<'w, 's, D, F> { +/// fn data(&self) -> Option> { +/// // We need to use `_inner` methods to return the full `'w` lifetime. +/// self.nested_query.get_inner(self.parent.parent()).ok() +/// } +/// } +/// ``` +/// +/// In order to make a query that returns the inner query data directly, +/// instead of through an intermediate `Item` struct, +/// you can implement `QueryData` manually by delegating to `NestedQuery`. +/// +/// ``` +/// # use bevy_ecs::{ +/// # archetype::Archetype, +/// # change_detection::Tick, +/// # component::{ComponentId, Components}, +/// # prelude::*, +/// # query::{ +/// # EcsAccessType, FilteredAccess, IterQueryData, NestedQuery, QueryData, QueryFilter, +/// # ReadOnlyQueryData, ReleaseStateQueryData, WorldQuery, +/// # }, +/// # storage::{Table, TableRow}, +/// # world::unsafe_world_cell::UnsafeWorldCell, +/// # }; +/// # +/// # #[derive(Component)] +/// # struct Data(usize); +/// # +/// # let mut world = World::new(); +/// # +/// // We want to create a relational query data +/// // that lets us query components on an entity's parent, +/// // like this: +/// let root = world.spawn(Data(3)).id(); +/// let child = world.spawn(ChildOf(root)).id(); +/// +/// let mut query = world.query::>(); +/// let &Data(data) = query.query(&mut world).get(child).unwrap(); +/// assert_eq!(data, 3); +/// +/// // This is the relational query data. +/// // This will never actually be constructed, +/// // and is only used as a `QueryData` type. +/// pub struct Parent(D, F); +/// +/// // A type alias to delegate the `QueryData` impls to. +/// // We need to refer to this type a lot, so the alias will help. +/// // This could also be a `#[derive(QueryData)]` type. +/// type ParentInner = ( +/// // This will query `ChildOf` on the entity itself, +/// // so we can find the parent entity +/// &'static ChildOf, +/// // This will provide a `Query` that we can use to +/// // query data on the parent entity +/// NestedQuery, +/// ); +/// +/// unsafe impl QueryData for Parent { +/// // Set `Item` to what we need for this relational query. +/// // Here we use the output of `D`. +/// type Item<'w, 's> = D::Item<'w, 's>; +/// +/// unsafe fn fetch<'w, 's>(state: &'s Self::State, fetch: &mut Self::Fetch<'w>, entity: Entity, table_row: TableRow) -> Option> { +/// // In `fetch`, first delegate to the type alias to get the parts: +/// let (&ChildOf(parent), nested_query) = +/// as QueryData>::fetch(state, fetch, entity, table_row)?; +/// // Then use the `NestedQuery` to get the data we need. +/// // We need to use `_inner` methods to return the full `'w` lifetime. +/// nested_query.get_inner(parent).ok() +/// } +/// +/// fn shrink<'wlong: 'wshort, 'wshort, 's>(item: Self::Item<'wlong, 's>) -> Self::Item<'wshort, 's> { +/// D::shrink(item) +/// } +/// +/// // Set `ReadOnly` to `Self`, +/// // as `NestedQuery` does not yet support mutable queries. +/// type ReadOnly = Self; +/// +/// // Delegate everything else on `QueryData` and `WorldQuery` to the type alias. +/// // This is sound for `unsafe` items because they delegate to the +/// // sound implementations on the type alias. +/// const IS_READ_ONLY: bool = as QueryData>::IS_READ_ONLY; +/// const IS_ARCHETYPAL: bool = as QueryData>::IS_ARCHETYPAL; +/// +/// fn iter_access(state: &Self::State) -> impl Iterator> { +/// as QueryData>::iter_access(state) +/// } /// } /// -/// impl<'w, 's> NameFromAItem<'w, 's> { -/// fn name(&self) -> Option<&str> { -/// self.query.get(self.a.0).ok().map(|name| &*name.0) +/// unsafe impl WorldQuery for Parent { +/// type Fetch<'w> = as WorldQuery>::Fetch<'w>; +/// type State = as WorldQuery>::State; +/// +/// fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> { +/// as WorldQuery>::shrink_fetch(fetch) +/// } +/// +/// unsafe fn init_fetch<'w, 's>(world: UnsafeWorldCell<'w>, state: &'s Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> { +/// as WorldQuery>::init_fetch(world, state, last_run, this_run) +/// } +/// +/// const IS_DENSE: bool = as WorldQuery>::IS_DENSE; +/// +/// unsafe fn set_archetype<'w, 's>(fetch: &mut Self::Fetch<'w>, state: &'s Self::State, archetype: &'w Archetype, table: &'w Table) { +/// as WorldQuery>::set_archetype(fetch, state, archetype, table) +/// } +/// +/// unsafe fn set_table<'w, 's>(fetch: &mut Self::Fetch<'w>, state: &'s Self::State, table: &'w Table) { +/// as WorldQuery>::set_table(fetch, state, table) +/// } +/// +/// fn update_component_access(state: &Self::State, access: &mut FilteredAccess) { +/// as WorldQuery>::update_component_access(state, access) +/// } +/// +/// fn init_state(world: &mut World) -> Self::State { +/// as WorldQuery>::init_state(world) +/// } +/// +/// fn get_state(components: &Components) -> Option { +/// as WorldQuery>::get_state(components) +/// } +/// +/// fn matches_component_set(state: &Self::State, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool { +/// as WorldQuery>::matches_component_set(state, set_contains_id) /// } /// } /// -/// fn system(query: Query) { -/// for item in query { -/// let name: Option<&str> = item.name(); +/// // Also impl `ReadOnlyQueryData`, `IterQueryData`, and `ReleaseStateQueryData` +/// // These are safe because they delegate to the type alias, which is also read-only. +/// // Do *not* impl `ArchetypeQueryData`, because `fetch` sometimes returns `None`, +/// // and do *not* impl `SingleEntityQueryData`, because `NestedQuery` accesses other entities. +/// unsafe impl ReadOnlyQueryData for Parent {} +/// +/// unsafe impl IterQueryData for Parent {} +/// +/// impl +/// ReleaseStateQueryData for Parent +/// { +/// fn release_state<'w>(item: Self::Item<'w, '_>) -> Self::Item<'w, 'static> { +/// D::release_state(item) /// } /// } /// ```