Skip to content

Commit 8700e11

Browse files
committed
add iter_related hierarchy query extension
1 parent b240b41 commit 8700e11

File tree

1 file changed

+135
-65
lines changed

1 file changed

+135
-65
lines changed

crates/bevy_hierarchy/src/query_extension.rs

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

33
use bevy_ecs::{
4-
entity::Entity,
4+
component::Component,
5+
entity::{Entity, VisitEntities},
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,104 +56,132 @@ 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 [`VisitEntities`].
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>
6985
where
70-
D::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
86+
D::ReadOnly: WorldQuery<Item<'w> = &'w C>,
87+
C: Component + VisitEntities;
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>
92+
where
93+
<D as QueryData>::ReadOnly: WorldQuery<Item<'w> = &'w C>,
94+
C: Component + VisitEntities,
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+
/// [`VisitEntities`].
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 + VisitEntities,
82110
{
83-
children_query: &'w Query<'w, 's, D, F>,
84-
vecdeque: VecDeque<Entity>,
111+
related_query: &'w Query<'w, 's, D, F>,
112+
vecdeque: VecDeque<(usize, 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 + VisitEntities,
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
96-
.get(entity)
97-
.into_iter()
98-
.flatten()
99-
.copied()
100-
.collect(),
122+
/// Create a new [`RelatedIter`].
123+
fn new(related_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
124+
let mut vecdeque = VecDeque::new();
125+
related_query.get(entity).into_iter().for_each(|t| {
126+
t.visit_entities(|entity| {
127+
vecdeque.push_back((1, entity));
128+
})
129+
});
130+
RelatedIter {
131+
related_query,
132+
vecdeque,
101133
}
102134
}
103-
}
104135

105-
impl<'w, 's, D: QueryData, F: QueryFilter> Iterator for DescendantIter<'w, 's, D, F>
106-
where
107-
D::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
108-
{
109-
type Item = Entity;
136+
fn next(&mut self) -> Option<(usize, Entity)> {
137+
let (depth, entity) = self.vecdeque.pop_front()?;
110138

111-
fn next(&mut self) -> Option<Self::Item> {
112-
let entity = self.vecdeque.pop_front()?;
113-
114-
if let Ok(children) = self.children_query.get(entity) {
115-
self.vecdeque.extend(children);
139+
if let Ok(children) = self.related_query.get(entity) {
140+
children.visit_entities(|entity| {
141+
self.vecdeque.push_back((depth + 1, entity));
142+
});
116143
}
117144

118-
Some(entity)
145+
Some((depth, entity))
119146
}
120-
}
121147

122-
/// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`].
123-
pub struct AncestorIter<'w, 's, D: QueryData, F: QueryFilter>
124-
where
125-
D::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
126-
{
127-
parent_query: &'w Query<'w, 's, D, F>,
128-
next: Option<Entity>,
148+
pub fn with_depth(self) -> RelatedDepthIter<'w, 's, C, D, F> {
149+
RelatedDepthIter(self)
150+
}
129151
}
130152

131-
impl<'w, 's, D: QueryData, F: QueryFilter> AncestorIter<'w, 's, D, F>
153+
impl<'w, 's, C, D, F> Iterator for RelatedIter<'w, 's, C, D, F>
132154
where
133-
D::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
155+
D: QueryData,
156+
F: QueryFilter,
157+
D::ReadOnly: WorldQuery<Item<'w> = &'w C>,
158+
C: Component + VisitEntities,
134159
{
135-
/// Returns a new [`AncestorIter`].
136-
pub fn new(parent_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
137-
AncestorIter {
138-
parent_query,
139-
next: Some(entity),
140-
}
160+
type Item = Entity;
161+
162+
fn next(&mut self) -> Option<Self::Item> {
163+
RelatedIter::next(self).map(|(_, e)| e)
141164
}
142165
}
143166

144-
impl<'w, 's, D: QueryData, F: QueryFilter> Iterator for AncestorIter<'w, 's, D, F>
167+
pub struct RelatedDepthIter<'w, 's, C, D, F>(RelatedIter<'w, 's, C, D, F>)
145168
where
146-
D::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
169+
D: QueryData,
170+
F: QueryFilter,
171+
D::ReadOnly: WorldQuery<Item<'w> = &'w C>,
172+
C: Component + VisitEntities;
173+
174+
impl<'w, 's, C, D, F> Iterator for RelatedDepthIter<'w, 's, C, D, F>
175+
where
176+
D: QueryData,
177+
F: QueryFilter,
178+
D::ReadOnly: WorldQuery<Item<'w> = &'w C>,
179+
C: Component + VisitEntities,
147180
{
148-
type Item = Entity;
181+
type Item = (usize, Entity);
149182

150183
fn next(&mut self) -> Option<Self::Item> {
151-
self.next = self.parent_query.get(self.next?).ok().map(Parent::get);
152-
self.next
184+
RelatedIter::next(&mut self.0)
153185
}
154186
}
155187

@@ -201,4 +233,42 @@ mod tests {
201233

202234
assert_eq!([&A(1), &A(0)], result.as_slice());
203235
}
236+
237+
#[test]
238+
fn related_children_iter() {
239+
let world = &mut World::new();
240+
241+
let [a, b, c, d] = std::array::from_fn(|i| world.spawn(A(i)).id());
242+
243+
world.entity_mut(a).add_children(&[b, c]);
244+
world.entity_mut(c).add_children(&[d]);
245+
246+
let mut system_state = SystemState::<(Query<&Children>, Query<&A>)>::new(world);
247+
let (children_query, a_query) = system_state.get(world);
248+
249+
let result: Vec<_> = children_query
250+
.iter_related(a)
251+
.with_depth()
252+
.filter_map(|(d, e)| Some((d, a_query.get(e).ok()?)))
253+
.collect();
254+
255+
assert_eq!([(1, &A(1)), (1, &A(2)), (2, &A(3))], result.as_slice());
256+
}
257+
258+
#[test]
259+
fn related_parent_iter() {
260+
let world = &mut World::new();
261+
262+
let [a, b, c] = std::array::from_fn(|i| world.spawn(A(i)).id());
263+
264+
world.entity_mut(a).add_children(&[b]);
265+
world.entity_mut(b).add_children(&[c]);
266+
267+
let mut system_state = SystemState::<(Query<&Parent>, Query<&A>)>::new(world);
268+
let (parent_query, a_query) = system_state.get(world);
269+
270+
let result: Vec<_> = a_query.iter_many(parent_query.iter_related(c)).collect();
271+
272+
assert_eq!([&A(1), &A(0)], result.as_slice());
273+
}
204274
}

0 commit comments

Comments
 (0)