Skip to content

Commit cabaf73

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

File tree

1 file changed

+208
-2
lines changed

1 file changed

+208
-2
lines changed

crates/bevy_ecs/src/query/iter.rs

Lines changed: 208 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
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,
11+
cmp::Ordering,
12+
fmt::{self, Debug, Formatter},
13+
iter::FusedIterator,
14+
mem::MaybeUninit,
15+
ops::Range,
16+
vec::IntoIter,
17+
};
1018

1119
use super::{QueryData, QueryFilter, ReadOnlyQueryData};
1220

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

11071192
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, I: Iterator> Iterator
@@ -1131,6 +1216,127 @@ where
11311216
{
11321217
}
11331218

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

0 commit comments

Comments
 (0)