Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/query/access_iter.rs
9334 views
1
use core::fmt::Display;
2
3
use crate::{
4
component::{ComponentId, Components},
5
query::{Access, QueryData},
6
};
7
use bevy_utils::BloomFilter;
8
9
// found by benchmarking
10
// too low, and smaller queries do unnecessary work
11
// maintaining the bloom filter for a handful of checks
12
// too high, and the benefit of a simpler loop
13
// is outweighed by the n^2 check
14
const USE_FILTER_THRESHOLD: usize = 4;
15
16
/// Check if `Q` has any internal conflicts.
17
#[inline(never)]
18
pub fn has_conflicts<Q: QueryData>(components: &Components) -> Result<(), QueryAccessError> {
19
let Some(state) = Q::get_state(components) else {
20
return Err(QueryAccessError::ComponentNotRegistered);
21
};
22
23
let result = if let Some(size) = Q::iter_access(&state).size_hint().1
24
&& size <= USE_FILTER_THRESHOLD
25
{
26
has_conflicts_small::<Q>(&state)
27
} else {
28
has_conflicts_large::<Q>(&state)
29
};
30
if let Err(e) = result {
31
panic!("{e}");
32
}
33
34
Ok(())
35
}
36
37
/// Check if `Q` has any internal conflicts by checking all pairs of accesses.
38
///
39
/// This is intended for queries with fewer components than [`USE_FILTER_THRESHOLD`].
40
/// Split from [`has_conflicts`] for easier testing.
41
fn has_conflicts_small<'a, Q: QueryData>(
42
state: &'a Q::State,
43
) -> Result<(), AccessConflictError<'a>> {
44
// we can optimize small sizes by caching the iteration result in an array on the stack
45
let mut inner_access = [EcsAccessType::Empty; USE_FILTER_THRESHOLD];
46
for (i, access) in Q::iter_access(state).enumerate() {
47
for access_other in inner_access.iter().take(i) {
48
if access.is_compatible(*access_other).is_err() {
49
return Err(AccessConflictError(access, *access_other));
50
}
51
}
52
inner_access[i] = access;
53
}
54
55
Ok(())
56
}
57
58
/// Check if `Q` has any internal conflicts using a bloom filter for efficiency.
59
///
60
/// This is intended for queries with more components than [`USE_FILTER_THRESHOLD`].
61
/// Split from [`has_conflicts`] for easier testing.
62
fn has_conflicts_large<'a, Q: QueryData>(
63
state: &'a Q::State,
64
) -> Result<(), AccessConflictError<'a>> {
65
// use a bloom filter as a linear time check if we need to run the longer, exact check
66
let mut filter = BloomFilter::<8, 2>::new();
67
for (i, access) in Q::iter_access(state).enumerate() {
68
let needs_check = match access {
69
EcsAccessType::Component(EcsAccessLevel::Read(component_id))
70
| EcsAccessType::Component(EcsAccessLevel::Write(component_id)) => {
71
filter.check_insert(&component_id.index())
72
}
73
EcsAccessType::Component(EcsAccessLevel::ReadAll)
74
| EcsAccessType::Component(EcsAccessLevel::WriteAll) => true,
75
EcsAccessType::Resource(ResourceAccessLevel::Read(resource_id))
76
| EcsAccessType::Resource(ResourceAccessLevel::Write(resource_id)) => {
77
filter.check_insert(&resource_id.index())
78
}
79
EcsAccessType::Access(access) => {
80
if access.has_read_all_resources() || access.has_write_all_resources() {
81
true
82
} else if let Ok(component_iter) = access.try_iter_component_access() {
83
let mut needs_check = false;
84
for kind in component_iter {
85
let index = match kind {
86
crate::query::ComponentAccessKind::Shared(id)
87
| crate::query::ComponentAccessKind::Exclusive(id)
88
| crate::query::ComponentAccessKind::Archetypal(id) => id.index(),
89
};
90
if filter.check_insert(&index) {
91
needs_check = true;
92
}
93
}
94
for resource_id in access.resource_reads_and_writes() {
95
if filter.check_insert(&resource_id.index()) {
96
needs_check = true;
97
}
98
}
99
needs_check
100
} else {
101
true
102
}
103
}
104
EcsAccessType::Empty => continue,
105
};
106
if needs_check {
107
// we MIGHT have a conflict, fallback to slow check
108
for (j, access_other) in Q::iter_access(state).enumerate() {
109
if i == j {
110
continue;
111
}
112
if access.is_compatible(access_other).is_err() {
113
return Err(AccessConflictError(access, access_other));
114
}
115
}
116
}
117
}
118
Ok(())
119
}
120
121
/// The data storage type that is being accessed.
122
#[derive(Copy, Clone, Debug, PartialEq, Hash)]
123
pub enum EcsAccessType<'a> {
124
/// Accesses [`Component`](crate::prelude::Component) data
125
Component(EcsAccessLevel),
126
/// Accesses [`Resource`](crate::prelude::Resource) data
127
Resource(ResourceAccessLevel),
128
/// borrowed access from [`WorldQuery::State`](crate::query::WorldQuery)
129
Access(&'a Access),
130
/// Does not access any data that can conflict.
131
Empty,
132
}
133
134
impl<'a> EcsAccessType<'a> {
135
/// Returns `Ok(())` if `self` and `other` are compatible. Returns a [`AccessConflictError`] otherwise.
136
#[inline(never)]
137
pub fn is_compatible(&self, other: Self) -> Result<(), AccessConflictError<'_>> {
138
use EcsAccessLevel::*;
139
use EcsAccessType::*;
140
141
match (*self, other) {
142
(Component(ReadAll), Component(Write(_)))
143
| (Component(Write(_)), Component(ReadAll))
144
| (Component(_), Component(WriteAll))
145
| (Component(WriteAll), Component(_)) => Err(AccessConflictError(*self, other)),
146
147
(Empty, _)
148
| (_, Empty)
149
| (Component(_), Resource(_))
150
| (Resource(_), Component(_))
151
// read only access doesn't conflict
152
| (Component(Read(_)), Component(Read(_)))
153
| (Component(ReadAll), Component(Read(_)))
154
| (Component(Read(_)), Component(ReadAll))
155
| (Component(ReadAll), Component(ReadAll))
156
| (Resource(ResourceAccessLevel::Read(_)), Resource(ResourceAccessLevel::Read(_))) => {
157
Ok(())
158
}
159
160
(Component(Read(id)), Component(Write(id_other)))
161
| (Component(Write(id)), Component(Read(id_other)))
162
| (Component(Write(id)), Component(Write(id_other)))
163
| (
164
Resource(ResourceAccessLevel::Read(id)),
165
Resource(ResourceAccessLevel::Write(id_other)),
166
)
167
| (
168
Resource(ResourceAccessLevel::Write(id)),
169
Resource(ResourceAccessLevel::Read(id_other)),
170
)
171
| (
172
Resource(ResourceAccessLevel::Write(id)),
173
Resource(ResourceAccessLevel::Write(id_other)),
174
) => if id == id_other {
175
Err(AccessConflictError(*self, other))
176
} else {
177
Ok(())
178
},
179
180
// Borrowed Access
181
(Component(Read(component_id)), Access(access))
182
| (Access(access), Component(Read(component_id))) => if access.has_component_write(component_id) {
183
Err(AccessConflictError(*self, other))
184
} else {
185
Ok(())
186
},
187
188
(Component(Write(component_id)), Access(access))
189
| (Access(access), Component(Write(component_id))) => if access.has_component_read(component_id) {
190
Err(AccessConflictError(*self, other))
191
} else {
192
Ok(())
193
},
194
195
(Component(ReadAll), Access(access))
196
| (Access(access), Component(ReadAll)) => if access.has_any_component_write() {
197
Err(AccessConflictError(*self, other))
198
} else {
199
Ok(())
200
},
201
202
(Component(WriteAll), Access(access))
203
| (Access(access), Component(WriteAll))=> if access.has_any_component_read() {
204
Err(AccessConflictError(*self, other))
205
} else {
206
Ok(())
207
},
208
209
(Resource(ResourceAccessLevel::Read(component_id)), Access(access))
210
| (Access(access), Resource(ResourceAccessLevel::Read(component_id))) => if access.has_resource_write(component_id) {
211
Err(AccessConflictError(*self, other))
212
} else {
213
Ok(())
214
},
215
(Resource(ResourceAccessLevel::Write(component_id)), Access(access))
216
| (Access(access), Resource(ResourceAccessLevel::Write(component_id))) => if access.has_resource_read(component_id) {
217
Err(AccessConflictError(*self, other))
218
} else {
219
Ok(())
220
},
221
222
(Access(access), Access(other_access)) => if access.is_compatible(other_access) {
223
Ok(())
224
} else {
225
Err(AccessConflictError(*self, other))
226
},
227
}
228
}
229
}
230
231
/// The way the data will be accessed and whether we take access on all the components on
232
/// an entity or just one component.
233
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
234
pub enum EcsAccessLevel {
235
/// Reads [`Component`](crate::prelude::Component) with [`ComponentId`]
236
Read(ComponentId),
237
/// Writes [`Component`](crate::prelude::Component) with [`ComponentId`]
238
Write(ComponentId),
239
/// Potentially reads all [`Component`](crate::prelude::Component)'s in the [`World`](crate::prelude::World)
240
ReadAll,
241
/// Potentially writes all [`Component`](crate::prelude::Component)'s in the [`World`](crate::prelude::World)
242
WriteAll,
243
}
244
245
/// Access level needed by [`QueryData`] fetch to the resource.
246
#[derive(Copy, Clone, Debug, PartialEq, Hash)]
247
pub enum ResourceAccessLevel {
248
/// Reads the resource with [`ComponentId`]
249
Read(ComponentId),
250
/// Writes the resource with [`ComponentId`]
251
Write(ComponentId),
252
}
253
254
/// Error returned from [`EcsAccessType::is_compatible`]
255
pub struct AccessConflictError<'a>(EcsAccessType<'a>, EcsAccessType<'a>);
256
257
impl Display for AccessConflictError<'_> {
258
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
259
use EcsAccessLevel::*;
260
use EcsAccessType::*;
261
262
let AccessConflictError(a, b) = self;
263
match (a, b) {
264
// ReadAll/WriteAll + Component conflicts
265
(Component(ReadAll), Component(Write(id)))
266
| (Component(Write(id)), Component(ReadAll)) => {
267
write!(
268
f,
269
"Component read all access conflicts with component {id:?} write."
270
)
271
}
272
(Component(WriteAll), Component(Write(id)))
273
| (Component(Write(id)), Component(WriteAll)) => {
274
write!(
275
f,
276
"Component write all access conflicts with component {id:?} write."
277
)
278
}
279
(Component(WriteAll), Component(Read(id)))
280
| (Component(Read(id)), Component(WriteAll)) => {
281
write!(
282
f,
283
"Component write all access conflicts with component {id:?} read."
284
)
285
}
286
(Component(WriteAll), Component(ReadAll))
287
| (Component(ReadAll), Component(WriteAll)) => {
288
write!(f, "Component write all conflicts with component read all.")
289
}
290
(Component(WriteAll), Component(WriteAll)) => {
291
write!(f, "Component write all conflicts with component write all.")
292
}
293
294
// Component + Component conflicts
295
(Component(Read(id)), Component(Write(id_other)))
296
| (Component(Write(id_other)), Component(Read(id))) => write!(
297
f,
298
"Component {id:?} read conflicts with component {id_other:?} write."
299
),
300
(Component(Write(id)), Component(Write(id_other))) => write!(
301
f,
302
"Component {id:?} write conflicts with component {id_other:?} write."
303
),
304
305
// Borrowed Access conflicts
306
(Access(_), Component(Read(id))) | (Component(Read(id)), Access(_)) => write!(
307
f,
308
"Access has a write that conflicts with component {id:?} read."
309
),
310
(Access(_), Component(Write(id))) | (Component(Write(id)), Access(_)) => write!(
311
f,
312
"Access has a read that conflicts with component {id:?} write."
313
),
314
(Access(_), Component(ReadAll)) | (Component(ReadAll), Access(_)) => write!(
315
f,
316
"Access has a write that conflicts with component read all"
317
),
318
(Access(_), Component(WriteAll)) | (Component(WriteAll), Access(_)) => write!(
319
f,
320
"Access has a read that conflicts with component write all"
321
),
322
(Access(_), Resource(ResourceAccessLevel::Read(id)))
323
| (Resource(ResourceAccessLevel::Read(id)), Access(_)) => write!(
324
f,
325
"Access has a write that conflicts with resource {id:?} read."
326
),
327
(Access(_), Resource(ResourceAccessLevel::Write(id)))
328
| (Resource(ResourceAccessLevel::Write(id)), Access(_)) => write!(
329
f,
330
"Access has a read that conflicts with resource {id:?} write."
331
),
332
(Access(_), Access(_)) => write!(f, "Access conflicts with other Access"),
333
334
_ => {
335
unreachable!("Other accesses should be compatible");
336
}
337
}
338
}
339
}
340
341
/// Error returned from [`has_conflicts`].
342
#[derive(Clone, Copy, Debug, PartialEq)]
343
pub enum QueryAccessError {
344
/// Component was not registered on world
345
ComponentNotRegistered,
346
/// Entity did not have the requested components
347
EntityDoesNotMatch,
348
}
349
350
impl core::error::Error for QueryAccessError {}
351
352
impl Display for QueryAccessError {
353
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
354
match *self {
355
QueryAccessError::ComponentNotRegistered => {
356
write!(
357
f,
358
"At least one component in Q was not registered in world.
359
Consider calling `World::register_component`"
360
)
361
}
362
QueryAccessError::EntityDoesNotMatch => {
363
write!(f, "Entity does not match Q")
364
}
365
}
366
}
367
}
368
369
#[cfg(test)]
370
mod tests {
371
use super::*;
372
use crate::{
373
prelude::Component,
374
query::WorldQuery,
375
world::{EntityMut, EntityMutExcept, EntityRef, EntityRefExcept, World},
376
};
377
378
#[derive(Component)]
379
struct C1;
380
381
#[derive(Component)]
382
struct C2;
383
384
fn setup_world() -> World {
385
let world = World::new();
386
let mut world = world;
387
world.register_component::<C1>();
388
world.register_component::<C2>();
389
world
390
}
391
392
#[test]
393
fn simple_compatible() {
394
let world = setup_world();
395
let c = world.components();
396
397
// Compatible
398
let state = <&mut C1 as WorldQuery>::get_state(c).unwrap();
399
assert!(has_conflicts_small::<&mut C1>(&state).is_ok());
400
assert!(has_conflicts_large::<&mut C1>(&state).is_ok());
401
assert!(has_conflicts::<&mut C1>(c).is_ok());
402
403
let state = <&C1 as WorldQuery>::get_state(c).unwrap();
404
assert!(has_conflicts_small::<&C1>(&state).is_ok());
405
assert!(has_conflicts_large::<&C1>(&state).is_ok());
406
assert!(has_conflicts::<&C1>(c).is_ok());
407
408
let state = <(&C1, &C1) as WorldQuery>::get_state(c).unwrap();
409
assert!(has_conflicts_small::<(&C1, &C1)>(&state).is_ok());
410
assert!(has_conflicts_large::<(&C1, &C1)>(&state).is_ok());
411
assert!(has_conflicts::<(&C1, &C1)>(c).is_ok());
412
}
413
414
#[test]
415
#[should_panic(expected = "conflicts")]
416
fn conflict_component_read_conflicts_write() {
417
let world = setup_world();
418
let c = world.components();
419
let state = <(&C1, &mut C1) as WorldQuery>::get_state(c).unwrap();
420
assert!(has_conflicts_small::<(&C1, &mut C1)>(&state).is_err());
421
assert!(has_conflicts_large::<(&C1, &mut C1)>(&state).is_err());
422
let _ = has_conflicts::<(&C1, &mut C1)>(c);
423
}
424
425
#[test]
426
#[should_panic(expected = "conflicts")]
427
fn conflict_component_write_conflicts_read() {
428
let world = setup_world();
429
let c = world.components();
430
let state = <(&mut C1, &C1) as WorldQuery>::get_state(c).unwrap();
431
assert!(has_conflicts_small::<(&mut C1, &C1)>(&state).is_err());
432
assert!(has_conflicts_large::<(&mut C1, &C1)>(&state).is_err());
433
let _ = has_conflicts::<(&mut C1, &C1)>(c);
434
}
435
436
#[test]
437
#[should_panic(expected = "conflicts")]
438
fn conflict_component_write_conflicts_write() {
439
let world = setup_world();
440
let c = world.components();
441
let state = <(&mut C1, &mut C1) as WorldQuery>::get_state(c).unwrap();
442
assert!(has_conflicts_small::<(&mut C1, &mut C1)>(&state).is_err());
443
assert!(has_conflicts_large::<(&mut C1, &mut C1)>(&state).is_err());
444
let _ = has_conflicts::<(&mut C1, &mut C1)>(c);
445
}
446
447
#[test]
448
fn entity_ref_compatible() {
449
let world = setup_world();
450
let c = world.components();
451
452
// Compatible
453
let state = <(EntityRef, &C1) as WorldQuery>::get_state(c).unwrap();
454
assert!(has_conflicts_small::<(EntityRef, &C1)>(&state).is_ok());
455
assert!(has_conflicts_large::<(EntityRef, &C1)>(&state).is_ok());
456
assert!(has_conflicts::<(EntityRef, &C1)>(c).is_ok());
457
458
let state = <(&C1, EntityRef) as WorldQuery>::get_state(c).unwrap();
459
assert!(has_conflicts_small::<(&C1, EntityRef)>(&state).is_ok());
460
assert!(has_conflicts_large::<(&C1, EntityRef)>(&state).is_ok());
461
assert!(has_conflicts::<(&C1, EntityRef)>(c).is_ok());
462
463
let state = <(EntityRef, EntityRef) as WorldQuery>::get_state(c).unwrap();
464
assert!(has_conflicts_small::<(EntityRef, EntityRef)>(&state).is_ok());
465
assert!(has_conflicts_large::<(EntityRef, EntityRef)>(&state).is_ok());
466
assert!(has_conflicts::<(EntityRef, EntityRef)>(c).is_ok());
467
}
468
469
#[test]
470
#[should_panic(expected = "conflicts")]
471
fn entity_ref_conflicts_component_write() {
472
let world = setup_world();
473
let c = world.components();
474
let state = <(EntityRef, &mut C1) as WorldQuery>::get_state(c).unwrap();
475
assert!(has_conflicts_small::<(EntityRef, &mut C1)>(&state).is_err());
476
assert!(has_conflicts_large::<(EntityRef, &mut C1)>(&state).is_err());
477
let _ = has_conflicts::<(EntityRef, &mut C1)>(c);
478
}
479
480
#[test]
481
#[should_panic(expected = "conflicts")]
482
fn component_write_conflicts_entity_ref() {
483
let world = setup_world();
484
let c = world.components();
485
let state = <(&mut C1, EntityRef) as WorldQuery>::get_state(c).unwrap();
486
assert!(has_conflicts_small::<(&mut C1, EntityRef)>(&state).is_err());
487
assert!(has_conflicts_large::<(&mut C1, EntityRef)>(&state).is_err());
488
let _ = has_conflicts::<(&mut C1, EntityRef)>(c);
489
}
490
491
#[test]
492
#[should_panic(expected = "conflicts")]
493
fn entity_mut_conflicts_component_read() {
494
let world = setup_world();
495
let c = world.components();
496
let state = <(EntityMut, &C1) as WorldQuery>::get_state(c).unwrap();
497
assert!(has_conflicts_small::<(EntityMut, &C1)>(&state).is_err());
498
assert!(has_conflicts_large::<(EntityMut, &C1)>(&state).is_err());
499
let _ = has_conflicts::<(EntityMut, &C1)>(c);
500
}
501
502
#[test]
503
#[should_panic(expected = "conflicts")]
504
fn component_read_conflicts_entity_mut() {
505
let world = setup_world();
506
let c = world.components();
507
let state = <(&C1, EntityMut) as WorldQuery>::get_state(c).unwrap();
508
assert!(has_conflicts_small::<(&C1, EntityMut)>(&state).is_err());
509
assert!(has_conflicts_large::<(&C1, EntityMut)>(&state).is_err());
510
let _ = has_conflicts::<(&C1, EntityMut)>(c);
511
}
512
513
#[test]
514
#[should_panic(expected = "conflicts")]
515
fn entity_mut_conflicts_component_write() {
516
let world = setup_world();
517
let c = world.components();
518
let state = <(EntityMut, &mut C1) as WorldQuery>::get_state(c).unwrap();
519
assert!(has_conflicts_small::<(EntityMut, &mut C1)>(&state).is_err());
520
assert!(has_conflicts_large::<(EntityMut, &mut C1)>(&state).is_err());
521
let _ = has_conflicts::<(EntityMut, &mut C1)>(c);
522
}
523
524
#[test]
525
#[should_panic(expected = "conflicts")]
526
fn component_write_conflicts_entity_mut() {
527
let world = setup_world();
528
let c = world.components();
529
let state = <(&mut C1, EntityMut) as WorldQuery>::get_state(c).unwrap();
530
assert!(has_conflicts_small::<(&mut C1, EntityMut)>(&state).is_err());
531
assert!(has_conflicts_large::<(&mut C1, EntityMut)>(&state).is_err());
532
let _ = has_conflicts::<(&mut C1, EntityMut)>(c);
533
}
534
535
#[test]
536
#[should_panic(expected = "conflicts")]
537
fn entity_mut_conflicts_entity_ref() {
538
let world = setup_world();
539
let c = world.components();
540
let state = <(EntityMut, EntityRef) as WorldQuery>::get_state(c).unwrap();
541
assert!(has_conflicts_small::<(EntityMut, EntityRef)>(&state).is_err());
542
assert!(has_conflicts_large::<(EntityMut, EntityRef)>(&state).is_err());
543
let _ = has_conflicts::<(EntityMut, EntityRef)>(c);
544
}
545
546
#[test]
547
#[should_panic(expected = "conflicts")]
548
fn entity_ref_conflicts_entity_mut() {
549
let world = setup_world();
550
let c = world.components();
551
let state = <(EntityRef, EntityMut) as WorldQuery>::get_state(c).unwrap();
552
assert!(has_conflicts_small::<(EntityRef, EntityMut)>(&state).is_err());
553
assert!(has_conflicts_large::<(EntityRef, EntityMut)>(&state).is_err());
554
let _ = has_conflicts::<(EntityRef, EntityMut)>(c);
555
}
556
557
#[test]
558
fn entity_ref_except_compatible() {
559
let world = setup_world();
560
let c = world.components();
561
562
// Compatible
563
let state = <(EntityRefExcept<C1>, &mut C1) as WorldQuery>::get_state(c).unwrap();
564
assert!(has_conflicts_small::<(EntityRefExcept<C1>, &mut C1)>(&state).is_ok());
565
assert!(has_conflicts_large::<(EntityRefExcept<C1>, &mut C1)>(&state).is_ok());
566
assert!(has_conflicts::<(EntityRefExcept<C1>, &mut C1)>(c).is_ok());
567
568
let state = <(&mut C1, EntityRefExcept<C1>) as WorldQuery>::get_state(c).unwrap();
569
assert!(has_conflicts_small::<(&mut C1, EntityRefExcept<C1>)>(&state).is_ok());
570
assert!(has_conflicts_large::<(&mut C1, EntityRefExcept<C1>)>(&state).is_ok());
571
assert!(has_conflicts::<(&mut C1, EntityRefExcept<C1>)>(c).is_ok());
572
573
let state = <(&C2, EntityRefExcept<C1>) as WorldQuery>::get_state(c).unwrap();
574
assert!(has_conflicts_small::<(&C2, EntityRefExcept<C1>)>(&state).is_ok());
575
assert!(has_conflicts_large::<(&C2, EntityRefExcept<C1>)>(&state).is_ok());
576
assert!(has_conflicts::<(&C2, EntityRefExcept<C1>)>(c).is_ok());
577
578
let state = <(&mut C1, EntityRefExcept<(C1, C2)>) as WorldQuery>::get_state(c).unwrap();
579
assert!(has_conflicts_small::<(&mut C1, EntityRefExcept<(C1, C2)>)>(&state).is_ok());
580
assert!(has_conflicts_large::<(&mut C1, EntityRefExcept<(C1, C2)>)>(&state).is_ok());
581
assert!(has_conflicts::<(&mut C1, EntityRefExcept<(C1, C2)>)>(c).is_ok());
582
583
let state = <(EntityRefExcept<(C1, C2)>, &mut C1) as WorldQuery>::get_state(c).unwrap();
584
assert!(has_conflicts_small::<(EntityRefExcept<(C1, C2)>, &mut C1)>(&state).is_ok());
585
assert!(has_conflicts_large::<(EntityRefExcept<(C1, C2)>, &mut C1)>(&state).is_ok());
586
assert!(has_conflicts::<(EntityRefExcept<(C1, C2)>, &mut C1)>(c).is_ok());
587
588
let state =
589
<(&mut C1, &mut C2, EntityRefExcept<(C1, C2)>) as WorldQuery>::get_state(c).unwrap();
590
assert!(
591
has_conflicts_small::<(&mut C1, &mut C2, EntityRefExcept<(C1, C2)>)>(&state).is_ok()
592
);
593
assert!(
594
has_conflicts_large::<(&mut C1, &mut C2, EntityRefExcept<(C1, C2)>)>(&state).is_ok()
595
);
596
assert!(has_conflicts::<(&mut C1, &mut C2, EntityRefExcept<(C1, C2)>)>(c).is_ok());
597
598
let state =
599
<(&mut C1, EntityRefExcept<(C1, C2)>, &mut C2) as WorldQuery>::get_state(c).unwrap();
600
assert!(
601
has_conflicts_small::<(&mut C1, EntityRefExcept<(C1, C2)>, &mut C2)>(&state).is_ok()
602
);
603
assert!(
604
has_conflicts_large::<(&mut C1, EntityRefExcept<(C1, C2)>, &mut C2)>(&state).is_ok()
605
);
606
assert!(has_conflicts::<(&mut C1, EntityRefExcept<(C1, C2)>, &mut C2)>(c).is_ok());
607
608
let state =
609
<(EntityRefExcept<(C1, C2)>, &mut C1, &mut C2) as WorldQuery>::get_state(c).unwrap();
610
assert!(
611
has_conflicts_small::<(EntityRefExcept<(C1, C2)>, &mut C1, &mut C2)>(&state).is_ok()
612
);
613
assert!(
614
has_conflicts_large::<(EntityRefExcept<(C1, C2)>, &mut C1, &mut C2)>(&state).is_ok()
615
);
616
assert!(has_conflicts::<(EntityRefExcept<(C1, C2)>, &mut C1, &mut C2)>(c).is_ok());
617
}
618
619
#[test]
620
#[should_panic(expected = "conflicts")]
621
fn entity_ref_except_conflicts_component_write() {
622
let world = setup_world();
623
let c = world.components();
624
let state = <(EntityRefExcept<C1>, &mut C2) as WorldQuery>::get_state(c).unwrap();
625
assert!(has_conflicts_small::<(EntityRefExcept<C1>, &mut C2)>(&state).is_err());
626
assert!(has_conflicts_large::<(EntityRefExcept<C1>, &mut C2)>(&state).is_err());
627
let _ = has_conflicts::<(EntityRefExcept<C1>, &mut C2)>(c);
628
}
629
630
#[test]
631
#[should_panic(expected = "conflicts")]
632
fn component_write_conflicts_entity_ref_except() {
633
let world = setup_world();
634
let c = world.components();
635
let state = <(&mut C2, EntityRefExcept<C1>) as WorldQuery>::get_state(c).unwrap();
636
assert!(has_conflicts_small::<(&mut C2, EntityRefExcept<C1>)>(&state).is_err());
637
assert!(has_conflicts_large::<(&mut C2, EntityRefExcept<C1>)>(&state).is_err());
638
let _ = has_conflicts::<(&mut C2, EntityRefExcept<C1>)>(c);
639
}
640
641
#[test]
642
fn entity_mut_except_compatible() {
643
let world = setup_world();
644
let c = world.components();
645
646
// Compatible
647
let state = <(EntityMutExcept<C1>, &mut C1) as WorldQuery>::get_state(c).unwrap();
648
assert!(has_conflicts_small::<(EntityMutExcept<C1>, &mut C1)>(&state).is_ok());
649
assert!(has_conflicts_large::<(EntityMutExcept<C1>, &mut C1)>(&state).is_ok());
650
assert!(has_conflicts::<(EntityMutExcept<C1>, &mut C1)>(c).is_ok());
651
652
let state = <(&mut C1, EntityMutExcept<C1>) as WorldQuery>::get_state(c).unwrap();
653
assert!(has_conflicts_small::<(&mut C1, EntityMutExcept<C1>)>(&state).is_ok());
654
assert!(has_conflicts_large::<(&mut C1, EntityMutExcept<C1>)>(&state).is_ok());
655
assert!(has_conflicts::<(&mut C1, EntityMutExcept<C1>)>(c).is_ok());
656
657
let state = <(&mut C1, EntityMutExcept<(C1, C2)>) as WorldQuery>::get_state(c).unwrap();
658
assert!(has_conflicts_small::<(&mut C1, EntityMutExcept<(C1, C2)>)>(&state).is_ok());
659
assert!(has_conflicts_large::<(&mut C1, EntityMutExcept<(C1, C2)>)>(&state).is_ok());
660
assert!(has_conflicts::<(&mut C1, EntityMutExcept<(C1, C2)>)>(c).is_ok());
661
662
let state = <(EntityMutExcept<(C1, C2)>, &mut C1) as WorldQuery>::get_state(c).unwrap();
663
assert!(has_conflicts_small::<(EntityMutExcept<(C1, C2)>, &mut C1)>(&state).is_ok());
664
assert!(has_conflicts_large::<(EntityMutExcept<(C1, C2)>, &mut C1)>(&state).is_ok());
665
assert!(has_conflicts::<(EntityMutExcept<(C1, C2)>, &mut C1)>(c).is_ok());
666
667
let state =
668
<(&mut C1, &mut C2, EntityMutExcept<(C1, C2)>) as WorldQuery>::get_state(c).unwrap();
669
assert!(
670
has_conflicts_small::<(&mut C1, &mut C2, EntityMutExcept<(C1, C2)>)>(&state).is_ok()
671
);
672
assert!(
673
has_conflicts_large::<(&mut C1, &mut C2, EntityMutExcept<(C1, C2)>)>(&state).is_ok()
674
);
675
assert!(has_conflicts::<(&mut C1, &mut C2, EntityMutExcept<(C1, C2)>)>(c).is_ok());
676
677
let state =
678
<(&mut C1, EntityMutExcept<(C1, C2)>, &mut C2) as WorldQuery>::get_state(c).unwrap();
679
assert!(
680
has_conflicts_small::<(&mut C1, EntityMutExcept<(C1, C2)>, &mut C2)>(&state).is_ok()
681
);
682
assert!(
683
has_conflicts_large::<(&mut C1, EntityMutExcept<(C1, C2)>, &mut C2)>(&state).is_ok()
684
);
685
assert!(has_conflicts::<(&mut C1, EntityMutExcept<(C1, C2)>, &mut C2)>(c).is_ok());
686
687
let state =
688
<(EntityMutExcept<(C1, C2)>, &mut C1, &mut C2) as WorldQuery>::get_state(c).unwrap();
689
assert!(
690
has_conflicts_small::<(EntityMutExcept<(C1, C2)>, &mut C1, &mut C2)>(&state).is_ok()
691
);
692
assert!(
693
has_conflicts_large::<(EntityMutExcept<(C1, C2)>, &mut C1, &mut C2)>(&state).is_ok()
694
);
695
assert!(has_conflicts::<(EntityMutExcept<(C1, C2)>, &mut C1, &mut C2)>(c).is_ok());
696
}
697
698
#[test]
699
#[should_panic(expected = "conflicts")]
700
fn entity_mut_except_conflicts_component_read() {
701
let world = setup_world();
702
let c = world.components();
703
let state = <(EntityMutExcept<C1>, &C2) as WorldQuery>::get_state(c).unwrap();
704
assert!(has_conflicts_small::<(EntityMutExcept<C1>, &C2)>(&state).is_err());
705
assert!(has_conflicts_large::<(EntityMutExcept<C1>, &C2)>(&state).is_err());
706
let _ = has_conflicts::<(EntityMutExcept<C1>, &C2)>(c);
707
}
708
709
#[test]
710
#[should_panic(expected = "conflicts")]
711
fn component_read_conflicts_entity_mut_except() {
712
let world = setup_world();
713
let c = world.components();
714
let state = <(&C2, EntityMutExcept<C1>) as WorldQuery>::get_state(c).unwrap();
715
assert!(has_conflicts_small::<(&C2, EntityMutExcept<C1>)>(&state).is_err());
716
assert!(has_conflicts_large::<(&C2, EntityMutExcept<C1>)>(&state).is_err());
717
let _ = has_conflicts::<(&C2, EntityMutExcept<C1>)>(c);
718
}
719
720
#[test]
721
#[should_panic(expected = "conflicts")]
722
fn entity_mut_except_conflicts_component_write() {
723
let world = setup_world();
724
let c = world.components();
725
let state = <(EntityMutExcept<C1>, &mut C2) as WorldQuery>::get_state(c).unwrap();
726
assert!(has_conflicts_small::<(EntityMutExcept<C1>, &mut C2)>(&state).is_err());
727
assert!(has_conflicts_large::<(EntityMutExcept<C1>, &mut C2)>(&state).is_err());
728
let _ = has_conflicts::<(EntityMutExcept<C1>, &mut C2)>(c);
729
}
730
731
#[test]
732
#[should_panic(expected = "conflicts")]
733
fn component_write_conflicts_entity_mut_except() {
734
let world = setup_world();
735
let c = world.components();
736
let state = <(&mut C2, EntityMutExcept<C1>) as WorldQuery>::get_state(c).unwrap();
737
assert!(has_conflicts_small::<(&mut C2, EntityMutExcept<C1>)>(&state).is_err());
738
assert!(has_conflicts_large::<(&mut C2, EntityMutExcept<C1>)>(&state).is_err());
739
let _ = has_conflicts::<(&mut C2, EntityMutExcept<C1>)>(c);
740
}
741
}
742
743