Skip to content

Commit f4f433e

Browse files
committed
add entities_all_unique to QueryManyIter
1 parent 1ec5cdf commit f4f433e

File tree

1 file changed

+202
-2
lines changed

1 file changed

+202
-2
lines changed

crates/bevy_ecs/src/query/iter.rs

Lines changed: 202 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use crate::{
22
archetype::{Archetype, ArchetypeEntity, Archetypes},
33
component::Tick,
4-
entity::{Entities, Entity},
4+
entity::{Entities, Entity, EntityHashSet},
55
query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState, StorageId},
66
storage::{Table, TableRow, Tables},
77
world::unsafe_world_cell::UnsafeWorldCell,
88
};
9-
use std::{borrow::Borrow, cmp::Ordering, iter::FusedIterator, mem::MaybeUninit, ops::Range};
9+
use std::{
10+
borrow::Borrow, cmp::Ordering, fmt::{self, Debug, Formatter}, iter::FusedIterator, mem::MaybeUninit, ops::Range, vec::IntoIter,
11+
};
1012

1113
use super::{QueryData, QueryFilter, ReadOnlyQueryData};
1214

@@ -1102,6 +1104,83 @@ where
11021104
// of any previously returned unique references first, thus preventing aliasing.
11031105
unsafe { self.fetch_next_aliased_unchecked().map(D::shrink) }
11041106
}
1107+
1108+
/// Checks for uniqueness in the `Entity` iterator `I`, returning a new Iterator on success.
1109+
/// Return `self` on failure.
1110+
/// This new iterator allows for mutable iteration without `fetch_next`.
1111+
/// # Example
1112+
/// ```
1113+
/// # use bevy_ecs::prelude::*;
1114+
/// # use std::ops::{Deref, DerefMut};
1115+
/// #
1116+
/// # #[derive(Component, Clone, Copy)]
1117+
/// # struct PartValue(usize);
1118+
/// #
1119+
/// # impl Deref for PartValue {
1120+
/// # type Target = usize;
1121+
/// #
1122+
/// # fn deref(&self) -> &Self::Target {
1123+
/// # &self.0
1124+
/// # }
1125+
/// # }
1126+
/// #
1127+
/// # impl DerefMut for PartValue {
1128+
/// # fn deref_mut(&mut self) -> &mut Self::Target {
1129+
/// # &mut self.0
1130+
/// # }
1131+
/// # }
1132+
/// #
1133+
/// # let mut world = World::new();
1134+
/// #
1135+
/// // Mutable `Iterator` trait iteration.
1136+
/// fn system(mut query: Query<&mut PartValue>) {
1137+
/// # let entity_list: Vec<Entity> = Vec::new();
1138+
/// #
1139+
/// let mut unique_iter = query.iter_many_mut(entity_list)
1140+
/// .entities_all_unique()
1141+
/// .expect("the entity_list only contains unique entities");
1142+
///
1143+
/// for mut part_value in unique_iter {
1144+
/// **part_value += 1;
1145+
/// }
1146+
/// }
1147+
/// #
1148+
/// # let mut schedule = Schedule::default();
1149+
/// # schedule.add_systems((system));
1150+
/// # schedule.run(&mut world);
1151+
/// ```
1152+
#[inline(always)]
1153+
pub fn entities_all_unique(
1154+
self,
1155+
) -> Result<
1156+
QueryManyUniqueIter<'w, 's, D, F, IntoIter<I::Item>>,
1157+
QueryManyIter<'w, 's, D, F, IntoIter<I::Item>>,
1158+
> {
1159+
let mut used = EntityHashSet::default();
1160+
let entities: Vec<_> = self.entity_iter.collect();
1161+
1162+
if entities.iter().all(move |e| used.insert(*e.borrow())) {
1163+
return Ok(QueryManyUniqueIter {
1164+
entity_iter: entities.into_iter(),
1165+
entities: self.entities,
1166+
tables: self.tables,
1167+
archetypes: self.archetypes,
1168+
fetch: self.fetch,
1169+
filter: self.filter,
1170+
query_state: self.query_state,
1171+
});
1172+
}
1173+
1174+
Err(QueryManyIter {
1175+
entity_iter: entities.into_iter(),
1176+
entities: self.entities,
1177+
tables: self.tables,
1178+
archetypes: self.archetypes,
1179+
fetch: self.fetch,
1180+
filter: self.filter,
1181+
query_state: self.query_state,
1182+
})
1183+
}
11051184
}
11061185

11071186
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, I: Iterator> Iterator
@@ -1131,6 +1210,127 @@ where
11311210
{
11321211
}
11331212

1213+
impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator> Debug for QueryManyIter<'w, 's, D, F, I>
1214+
where
1215+
I::Item: Borrow<Entity>
1216+
{
1217+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1218+
f.debug_struct("QueryManyIter").finish()
1219+
}
1220+
}
1221+
1222+
/// An [`Iterator`] over the query items generated from an iterator of unique [`Entity`]s.
1223+
///
1224+
/// Items are returned in the order of the provided iterator.
1225+
/// Entities that don't match the query are skipped.
1226+
///
1227+
/// In contrast with `QueryManyIter`, this allows for mutable iteration without a `fetch_next` method.
1228+
///
1229+
/// This struct is created by the [`QueryManyIter::entities_all_unique`] method.
1230+
pub struct QueryManyUniqueIter<'w, 's, D: QueryData, F: QueryFilter, I: Iterator>
1231+
where
1232+
I::Item: Borrow<Entity>,
1233+
{
1234+
entity_iter: I,
1235+
entities: &'w Entities,
1236+
tables: &'w Tables,
1237+
archetypes: &'w Archetypes,
1238+
fetch: D::Fetch<'w>,
1239+
filter: F::Fetch<'w>,
1240+
query_state: &'s QueryState<D, F>,
1241+
}
1242+
1243+
impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator> QueryManyUniqueIter<'w, 's, D, F, I>
1244+
where
1245+
I::Item: Borrow<Entity>,
1246+
{
1247+
// Entities are guaranteed to be unique, so no lifetime shrinking needed for mutable iteration.
1248+
#[inline(always)]
1249+
fn fetch_next(&mut self) -> Option<D::Item<'w>> {
1250+
for entity in self.entity_iter.by_ref() {
1251+
let entity = *entity.borrow();
1252+
let Some(location) = self.entities.get(entity) else {
1253+
continue;
1254+
};
1255+
1256+
if !self
1257+
.query_state
1258+
.matched_archetypes
1259+
.contains(location.archetype_id.index())
1260+
{
1261+
continue;
1262+
}
1263+
let (archetype, table);
1264+
// SAFETY:
1265+
// `tables` and `archetypes` belong to the same world that the [`QueryIter`]
1266+
// was initialized for.
1267+
unsafe {
1268+
archetype = self
1269+
.archetypes
1270+
.get(location.archetype_id)
1271+
.debug_checked_unwrap();
1272+
table = self.tables.get(location.table_id).debug_checked_unwrap();
1273+
}
1274+
// SAFETY: `archetype` is from the world that `fetch/filter` were created for,
1275+
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
1276+
unsafe {
1277+
D::set_archetype(
1278+
&mut self.fetch,
1279+
&self.query_state.fetch_state,
1280+
archetype,
1281+
table,
1282+
);
1283+
}
1284+
// SAFETY: `table` is from the world that `fetch/filter` were created for,
1285+
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
1286+
unsafe {
1287+
F::set_archetype(
1288+
&mut self.filter,
1289+
&self.query_state.filter_state,
1290+
archetype,
1291+
table,
1292+
);
1293+
}
1294+
1295+
// SAFETY: set_archetype was called prior.
1296+
// `location.archetype_row` is an archetype index row in range of the current archetype, because if it was not, the match above would have `continue`d
1297+
if unsafe { F::filter_fetch(&mut self.filter, entity, location.table_row) } {
1298+
// SAFETY:
1299+
// - set_archetype was called prior, `location.archetype_row` is an archetype index in range of the current archetype
1300+
// - fetch is only called once for each entity.
1301+
return Some(unsafe { D::fetch(&mut self.fetch, entity, location.table_row) });
1302+
}
1303+
}
1304+
None
1305+
}
1306+
}
1307+
1308+
impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator> Iterator
1309+
for QueryManyUniqueIter<'w, 's, D, F, I>
1310+
where
1311+
I::Item: Borrow<Entity>,
1312+
{
1313+
type Item = D::Item<'w>;
1314+
1315+
#[inline(always)]
1316+
fn next(&mut self) -> Option<Self::Item> {
1317+
self.fetch_next()
1318+
}
1319+
1320+
fn size_hint(&self) -> (usize, Option<usize>) {
1321+
let (_, max_size) = self.entity_iter.size_hint();
1322+
(0, max_size)
1323+
}
1324+
}
1325+
1326+
// This is correct as [`QueryManyIter`] always returns `None` once exhausted.
1327+
impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator> FusedIterator
1328+
for QueryManyUniqueIter<'w, 's, D, F, I>
1329+
where
1330+
I::Item: Borrow<Entity>,
1331+
{
1332+
}
1333+
11341334
/// An iterator over `K`-sized combinations of query items without repetition.
11351335
///
11361336
/// A combination is an arrangement of a collection of items where order does not matter.

0 commit comments

Comments
 (0)