@@ -198,27 +198,15 @@ where
198
198
) -> Result < [ <Q :: ReadOnlyFetch as Fetch < ' w , ' s > >:: Item ; N ] , QueryEntityError > {
199
199
self . update_archetypes ( world) ;
200
200
201
- let array_of_results = entities. map ( |entity| {
202
- // SAFETY: query is read only
203
- unsafe {
204
- self . get_unchecked_manual :: < Q :: ReadOnlyFetch > (
205
- world,
206
- entity,
207
- world. last_change_tick ( ) ,
208
- world. read_change_tick ( ) ,
209
- )
210
- }
211
- } ) ;
212
-
213
- // If any of the entities were not present, return an error
214
- for result in & array_of_results {
215
- if let Err ( QueryEntityError :: NoSuchEntity ( entity) ) = result {
216
- return Err ( QueryEntityError :: NoSuchEntity ( * entity) ) ;
217
- }
201
+ // SAFE: query is read-only
202
+ unsafe {
203
+ self . get_multiple_unchecked_manual :: < Q :: ReadOnlyFetch > (
204
+ world,
205
+ entities,
206
+ world. last_change_tick ( ) ,
207
+ world. change_tick ( ) ,
208
+ )
218
209
}
219
-
220
- // Since we have verified that all entities are present, we can safely unwrap
221
- Ok ( array_of_results. map ( |result| result. unwrap ( ) ) )
222
210
}
223
211
224
212
/// Gets the query result for the given [`World`] and [`Entity`].
@@ -288,35 +276,17 @@ where
288
276
) -> Result < [ <Q :: Fetch as Fetch < ' w , ' s > >:: Item ; N ] , QueryEntityError > {
289
277
self . update_archetypes ( world) ;
290
278
291
- for i in 0 ..N {
292
- for j in 0 ..i {
293
- if entities[ i] == entities[ j] {
294
- return Err ( QueryEntityError :: AliasedMutability ( entities[ i] ) ) ;
295
- }
296
- }
297
- }
279
+ verify_entities_unique ( entities) ?;
298
280
299
- let array_of_results = entities. map ( |entity| {
300
- // SAFETY: entity list is checked for uniqueness, and we require exclusive access to the World
301
- unsafe {
302
- self . get_unchecked_manual :: < Q :: Fetch > (
303
- world,
304
- entity,
305
- world. last_change_tick ( ) ,
306
- world. read_change_tick ( ) ,
307
- )
308
- }
309
- } ) ;
310
-
311
- // If any of the entities were not present, return an error
312
- for result in & array_of_results {
313
- if let Err ( QueryEntityError :: NoSuchEntity ( entity) ) = result {
314
- return Err ( QueryEntityError :: NoSuchEntity ( * entity) ) ;
315
- }
281
+ // SAFE: method requires exclusive world access, and entities are checked for uniqueness
282
+ unsafe {
283
+ self . get_multiple_unchecked_manual :: < Q :: Fetch > (
284
+ world,
285
+ entities,
286
+ world. last_change_tick ( ) ,
287
+ world. change_tick ( ) ,
288
+ )
316
289
}
317
-
318
- // Since we have verified that all entities are present, we can safely unwrap
319
- Ok ( array_of_results. map ( |result| result. unwrap ( ) ) )
320
290
}
321
291
322
292
#[ inline]
@@ -396,6 +366,47 @@ where
396
366
}
397
367
}
398
368
369
+ /// Gets the query results for the given [`World`] and array of [`Entity`], where the last change and
370
+ /// the current change tick are given.
371
+ ///
372
+ /// # Safety
373
+ /// This does not check for mutable query correctness. To be safe, make sure mutable queries
374
+ /// have unique access to the components they query.
375
+ ///
376
+ /// If you are calling this method with a mutable query, you must verify that `entities` is free of duplicates:
377
+ /// use [`verify_entities_unique`] to do so efficiently for small `N`.
378
+ pub ( crate ) unsafe fn get_multiple_unchecked_manual <
379
+ ' s ,
380
+ ' w ,
381
+ QF : Fetch < ' w , ' s , State = Q :: State > ,
382
+ const N : usize ,
383
+ > (
384
+ & ' s self ,
385
+ world : & ' w World ,
386
+ entities : [ Entity ; N ] ,
387
+ last_change_tick : u32 ,
388
+ change_tick : u32 ,
389
+ ) -> Result < [ <QF as Fetch >:: Item ; N ] , QueryEntityError > {
390
+ let array_of_results = entities. map ( |entity| {
391
+ self . get_unchecked_manual :: < QF > (
392
+ world,
393
+ entity,
394
+ world. last_change_tick ( ) ,
395
+ world. read_change_tick ( ) ,
396
+ )
397
+ } ) ;
398
+
399
+ // If any of the entities were not present, return an error
400
+ for result in & array_of_results {
401
+ if let Err ( QueryEntityError :: NoSuchEntity ( entity) ) = result {
402
+ return Err ( QueryEntityError :: NoSuchEntity ( * entity) ) ;
403
+ }
404
+ }
405
+
406
+ // Since we have verified that all entities are present, we can safely unwrap
407
+ Ok ( array_of_results. map ( |result| result. unwrap ( ) ) )
408
+ }
409
+
399
410
/// Returns an [`Iterator`] over the query results for the given [`World`].
400
411
///
401
412
/// This can only be called for read-only queries, see [`Self::iter_mut`] for write-queries.
@@ -890,3 +901,17 @@ pub enum QueryEntityError {
890
901
#[ error( "The entity was requested mutably more than once." ) ]
891
902
AliasedMutability ( Entity ) ,
892
903
}
904
+
905
+ #[ inline]
906
+ pub ( crate ) fn verify_entities_unique < const N : usize > (
907
+ entities : [ Entity ; N ] ,
908
+ ) -> Result < ( ) , QueryEntityError > {
909
+ for i in 0 ..N {
910
+ for j in 0 ..i {
911
+ if entities[ i] == entities[ j] {
912
+ return Err ( QueryEntityError :: AliasedMutability ( entities[ i] ) ) ;
913
+ }
914
+ }
915
+ }
916
+ Ok ( ( ) )
917
+ }
0 commit comments