Skip to content

Commit 17bc758

Browse files
committed
add iter_related hierarchy query extension
1 parent c5be438 commit 17bc758

File tree

1 file changed

+102
-64
lines changed

1 file changed

+102
-64
lines changed

crates/bevy_hierarchy/src/query_extension.rs

Lines changed: 102 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::collections::VecDeque;
22

33
use bevy_ecs::{
4-
entity::Entity,
4+
component::Component,
5+
entity::{Entity, IterEntities},
56
query::{QueryData, QueryFilter, WorldQuery},
67
system::Query,
78
};
@@ -30,9 +31,12 @@ pub trait HierarchyQueryExt<'w, 's, D: QueryData, F: QueryFilter> {
3031
/// }
3132
/// # bevy_ecs::system::assert_is_system(system);
3233
/// ```
33-
fn iter_descendants(&'w self, entity: Entity) -> DescendantIter<'w, 's, D, F>
34+
fn iter_descendants(&'w self, entity: Entity) -> RelatedIter<'w, 's, Children, D, F>
3435
where
35-
D::ReadOnly: WorldQuery<Item<'w> = &'w Children>;
36+
D::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
37+
{
38+
self.iter_related(entity)
39+
}
3640

3741
/// Returns an [`Iterator`] of [`Entity`]s over all of `entity`s ancestors.
3842
///
@@ -52,102 +56,102 @@ pub trait HierarchyQueryExt<'w, 's, D: QueryData, F: QueryFilter> {
5256
/// }
5357
/// # bevy_ecs::system::assert_is_system(system);
5458
/// ```
55-
fn iter_ancestors(&'w self, entity: Entity) -> AncestorIter<'w, 's, D, F>
56-
where
57-
D::ReadOnly: WorldQuery<Item<'w> = &'w Parent>;
58-
}
59-
60-
impl<'w, 's, D: QueryData, F: QueryFilter> HierarchyQueryExt<'w, 's, D, F> for Query<'w, 's, D, F> {
61-
fn iter_descendants(&'w self, entity: Entity) -> DescendantIter<'w, 's, D, F>
59+
fn iter_ancestors(&'w self, entity: Entity) -> RelatedIter<'w, 's, Parent, D, F>
6260
where
63-
D::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
61+
D::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
6462
{
65-
DescendantIter::new(self, entity)
63+
self.iter_related(entity)
6664
}
6765

68-
fn iter_ancestors(&'w self, entity: Entity) -> AncestorIter<'w, 's, D, F>
66+
/// Returns an [`Iterator`] of [`Entity`]'s over all of `entity`'s `C` relations.
67+
///
68+
/// Can only be called on a [`Query`] of `C` (i.e. `Query<&C>`), where `C`
69+
/// is some type implementing [`IterEntities`].
70+
/// # Examples
71+
/// ```
72+
/// # use bevy_ecs::prelude::*;
73+
/// # use bevy_hierarchy::prelude::*;
74+
/// # #[derive(Component)]
75+
/// # struct Marker;
76+
/// fn system(query: Query<Entity, With<Marker>>, parent_query: Query<&Parent>) {
77+
/// let entity = query.single();
78+
/// for ancestor in parent_query.iter_related(entity) {
79+
/// // Do something!
80+
/// }
81+
/// }
82+
/// # bevy_ecs::system::assert_is_system(system);
83+
/// ```
84+
fn iter_related<C>(&'w self, entity: Entity) -> RelatedIter<'w, 's, C, D, F>
85+
where
86+
D::ReadOnly: WorldQuery<Item<'w> = &'w C>,
87+
C: Component + IterEntities;
88+
}
89+
90+
impl<'w, 's, D: QueryData, F: QueryFilter> HierarchyQueryExt<'w, 's, D, F> for Query<'w, 's, D, F> {
91+
fn iter_related<C>(&'w self, entity: Entity) -> RelatedIter<'w, 's, C, D, F>
6992
where
70-
D::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
93+
<D as QueryData>::ReadOnly: WorldQuery<Item<'w> = &'w C>,
94+
C: Component + IterEntities,
7195
{
72-
AncestorIter::new(self, entity)
96+
RelatedIter::new(self, entity)
7397
}
7498
}
7599

76-
/// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`].
100+
/// An iterator over entities related via some component `C` that implements
101+
/// [`IterEntities`].
77102
///
78103
/// Traverses the hierarchy breadth-first.
79-
pub struct DescendantIter<'w, 's, D: QueryData, F: QueryFilter>
104+
pub struct RelatedIter<'w, 's, C, D, F>
80105
where
81-
D::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
106+
D: QueryData,
107+
F: QueryFilter,
108+
D::ReadOnly: WorldQuery<Item<'w> = &'w C>,
109+
C: Component + IterEntities,
82110
{
83-
children_query: &'w Query<'w, 's, D, F>,
111+
related_query: &'w Query<'w, 's, D, F>,
84112
vecdeque: VecDeque<Entity>,
85113
}
86114

87-
impl<'w, 's, D: QueryData, F: QueryFilter> DescendantIter<'w, 's, D, F>
115+
impl<'w, 's, C, D, F> RelatedIter<'w, 's, C, D, F>
88116
where
89-
D::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
117+
D: QueryData,
118+
F: QueryFilter,
119+
D::ReadOnly: WorldQuery<Item<'w> = &'w C>,
120+
C: Component + IterEntities,
90121
{
91-
/// Returns a new [`DescendantIter`].
92-
pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
93-
DescendantIter {
94-
children_query,
95-
vecdeque: children_query.get(entity).into_iter().flatten().collect(),
122+
/// Create a new [`RelatedIter`].
123+
pub fn new(related_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
124+
RelatedIter {
125+
related_query,
126+
vecdeque: related_query
127+
.get(entity)
128+
.iter()
129+
.flat_map(|t| t.iter_entities())
130+
.collect(),
96131
}
97132
}
98133
}
99134

100-
impl<'w, 's, D: QueryData, F: QueryFilter> Iterator for DescendantIter<'w, 's, D, F>
135+
impl<'w, 's, C, D, F> Iterator for RelatedIter<'w, 's, C, D, F>
101136
where
102-
D::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
137+
D: QueryData,
138+
F: QueryFilter,
139+
D::ReadOnly: WorldQuery<Item<'w> = &'w C>,
140+
C: Component + IterEntities,
103141
{
104142
type Item = Entity;
105143

106144
fn next(&mut self) -> Option<Self::Item> {
107145
let entity = self.vecdeque.pop_front()?;
108146

109-
if let Ok(children) = self.children_query.get(entity) {
110-
self.vecdeque.extend(children);
147+
if let Ok(children) = self.related_query.get(entity) {
148+
self.vecdeque.extend(children.iter_entities());
111149
}
112150

113151
Some(entity)
114152
}
115153
}
116154

117-
/// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`].
118-
pub struct AncestorIter<'w, 's, D: QueryData, F: QueryFilter>
119-
where
120-
D::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
121-
{
122-
parent_query: &'w Query<'w, 's, D, F>,
123-
next: Option<Entity>,
124-
}
125-
126-
impl<'w, 's, D: QueryData, F: QueryFilter> AncestorIter<'w, 's, D, F>
127-
where
128-
D::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
129-
{
130-
/// Returns a new [`AncestorIter`].
131-
pub fn new(parent_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
132-
AncestorIter {
133-
parent_query,
134-
next: Some(entity),
135-
}
136-
}
137-
}
138-
139-
impl<'w, 's, D: QueryData, F: QueryFilter> Iterator for AncestorIter<'w, 's, D, F>
140-
where
141-
D::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
142-
{
143-
type Item = Entity;
144-
145-
fn next(&mut self) -> Option<Self::Item> {
146-
self.next = self.parent_query.get(self.next?).ok().map(Parent::get);
147-
self.next
148-
}
149-
}
150-
151155
#[cfg(test)]
152156
mod tests {
153157
use bevy_ecs::{
@@ -196,4 +200,38 @@ mod tests {
196200

197201
assert_eq!([&A(1), &A(0)], result.as_slice());
198202
}
203+
204+
#[test]
205+
fn related_children_iter() {
206+
let world = &mut World::new();
207+
208+
let [a, b, c, d] = std::array::from_fn(|i| world.spawn(A(i)).id());
209+
210+
world.entity_mut(a).add_children(&[b, c]);
211+
world.entity_mut(c).add_children(&[d]);
212+
213+
let mut system_state = SystemState::<(Query<&Children>, Query<&A>)>::new(world);
214+
let (children_query, a_query) = system_state.get(world);
215+
216+
let result: Vec<_> = a_query.iter_many(children_query.iter_related(a)).collect();
217+
218+
assert_eq!([&A(1), &A(2), &A(3)], result.as_slice());
219+
}
220+
221+
#[test]
222+
fn related_parent_iter() {
223+
let world = &mut World::new();
224+
225+
let [a, b, c] = std::array::from_fn(|i| world.spawn(A(i)).id());
226+
227+
world.entity_mut(a).add_children(&[b]);
228+
world.entity_mut(b).add_children(&[c]);
229+
230+
let mut system_state = SystemState::<(Query<&Parent>, Query<&A>)>::new(world);
231+
let (parent_query, a_query) = system_state.get(world);
232+
233+
let result: Vec<_> = a_query.iter_many(parent_query.iter_related(c)).collect();
234+
235+
assert_eq!([&A(1), &A(0)], result.as_slice());
236+
}
199237
}

0 commit comments

Comments
 (0)