Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/world/entity_access/mod.rs
9367 views
1
mod component_fetch;
2
mod entity_mut;
3
mod entity_ref;
4
mod entry;
5
mod except;
6
mod filtered;
7
mod world_mut;
8
9
pub use component_fetch::*;
10
pub use entity_mut::*;
11
pub use entity_ref::*;
12
pub use entry::*;
13
pub use except::*;
14
pub use filtered::*;
15
pub use world_mut::*;
16
17
#[cfg(test)]
18
mod tests {
19
use alloc::{vec, vec::Vec};
20
use bevy_ptr::{OwningPtr, Ptr};
21
use core::panic::AssertUnwindSafe;
22
use std::sync::OnceLock;
23
24
use crate::change_detection::Tick;
25
use crate::lifecycle::HookContext;
26
use crate::query::QueryAccessError;
27
use crate::{
28
change_detection::{MaybeLocation, MutUntyped},
29
component::ComponentId,
30
prelude::*,
31
resource::IsResource,
32
system::{assert_is_system, RunSystemOnce as _},
33
world::{error::EntityComponentError, DeferredWorld, FilteredEntityMut, FilteredEntityRef},
34
};
35
36
use super::{EntityMutExcept, EntityRefExcept};
37
38
#[derive(Component, Clone, Copy, Debug, PartialEq)]
39
struct TestComponent(u32);
40
41
#[derive(Component, Clone, Copy, Debug, PartialEq)]
42
#[component(storage = "SparseSet")]
43
struct TestComponent2(u32);
44
45
#[derive(Component)]
46
struct Marker;
47
48
#[derive(Component)]
49
#[component(on_add = despawn_on_add)]
50
struct DespawnOnAdd;
51
52
fn despawn_on_add(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
53
world.commands().entity(entity).despawn();
54
}
55
56
#[test]
57
fn entity_ref_get_by_id() {
58
let mut world = World::new();
59
let entity = world.spawn(TestComponent(42)).id();
60
let component_id = world
61
.components()
62
.get_valid_id(core::any::TypeId::of::<TestComponent>())
63
.unwrap();
64
65
let entity = world.entity(entity);
66
let test_component = entity.get_by_id(component_id).unwrap();
67
// SAFETY: points to a valid `TestComponent`
68
let test_component = unsafe { test_component.deref::<TestComponent>() };
69
70
assert_eq!(test_component.0, 42);
71
}
72
73
#[test]
74
fn entity_mut_get_by_id() {
75
let mut world = World::new();
76
let entity = world.spawn(TestComponent(42)).id();
77
let component_id = world
78
.components()
79
.get_valid_id(core::any::TypeId::of::<TestComponent>())
80
.unwrap();
81
82
let mut entity_mut = world.entity_mut(entity);
83
let mut test_component = entity_mut.get_mut_by_id(component_id).unwrap();
84
{
85
test_component.set_changed();
86
let test_component =
87
// SAFETY: `test_component` has unique access of the `EntityWorldMut` and is not used afterwards
88
unsafe { test_component.into_inner().deref_mut::<TestComponent>() };
89
test_component.0 = 43;
90
}
91
92
let entity = world.entity(entity);
93
let test_component = entity.get_by_id(component_id).unwrap();
94
// SAFETY: `TestComponent` is the correct component type
95
let test_component = unsafe { test_component.deref::<TestComponent>() };
96
97
assert_eq!(test_component.0, 43);
98
}
99
100
#[test]
101
fn entity_ref_get_by_id_invalid_component_id() {
102
let invalid_component_id = ComponentId::new(usize::MAX);
103
104
let mut world = World::new();
105
let entity = world.spawn_empty().id();
106
let entity = world.entity(entity);
107
assert!(entity.get_by_id(invalid_component_id).is_err());
108
}
109
110
#[test]
111
fn entity_mut_get_by_id_invalid_component_id() {
112
let invalid_component_id = ComponentId::new(usize::MAX);
113
114
let mut world = World::new();
115
let mut entity = world.spawn_empty();
116
assert!(entity.get_by_id(invalid_component_id).is_err());
117
assert!(entity.get_mut_by_id(invalid_component_id).is_err());
118
}
119
120
#[derive(Resource)]
121
struct R(usize);
122
123
#[test]
124
fn entity_mut_resource_scope() {
125
// Keep in sync with the `resource_scope` test in lib.rs
126
let mut world = World::new();
127
let mut entity = world.spawn_empty();
128
129
assert!(entity.try_resource_scope::<R, _>(|_, _| {}).is_none());
130
entity.world_scope(|world| world.insert_resource(R(0)));
131
entity.resource_scope(|entity: &mut EntityWorldMut, mut value: Mut<R>| {
132
value.0 += 1;
133
assert!(!entity.world().contains_resource::<R>());
134
});
135
assert_eq!(entity.resource::<R>().0, 1);
136
}
137
138
#[test]
139
fn entity_mut_resource_scope_panic() {
140
let mut world = World::new();
141
world.insert_resource(R(0));
142
143
let mut entity = world.spawn_empty();
144
let old_location = entity.location();
145
let result = std::panic::catch_unwind(AssertUnwindSafe(|| {
146
entity.resource_scope(|entity: &mut EntityWorldMut, _: Mut<R>| {
147
// Change the entity's `EntityLocation`.
148
entity.insert(TestComponent(0));
149
150
// Ensure that the entity location still gets updated even in case of a panic.
151
panic!("this should get caught by the outer scope")
152
});
153
}));
154
assert!(result.is_err());
155
156
// Ensure that the location has been properly updated.
157
assert_ne!(entity.location(), old_location);
158
}
159
160
// regression test for https://github.com/bevyengine/bevy/pull/7387
161
#[test]
162
fn entity_mut_world_scope_panic() {
163
let mut world = World::new();
164
165
let mut entity = world.spawn_empty();
166
let old_location = entity.location();
167
let id = entity.id();
168
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
169
entity.world_scope(|w| {
170
// Change the entity's `EntityLocation`, which invalidates the original `EntityWorldMut`.
171
// This will get updated at the end of the scope.
172
w.entity_mut(id).insert(TestComponent(0));
173
174
// Ensure that the entity location still gets updated even in case of a panic.
175
panic!("this should get caught by the outer scope")
176
});
177
}));
178
assert!(res.is_err());
179
180
// Ensure that the location has been properly updated.
181
assert_ne!(entity.location(), old_location);
182
}
183
184
#[test]
185
fn entity_mut_reborrow_scope_panic() {
186
let mut world = World::new();
187
188
let mut entity = world.spawn_empty();
189
let old_location = entity.location();
190
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
191
entity.reborrow_scope(|mut entity| {
192
// Change the entity's `EntityLocation`, which invalidates the original `EntityWorldMut`.
193
// This will get updated at the end of the scope.
194
entity.insert(TestComponent(0));
195
196
// Ensure that the entity location still gets updated even in case of a panic.
197
panic!("this should get caught by the outer scope")
198
});
199
}));
200
assert!(res.is_err());
201
202
// Ensure that the location has been properly updated.
203
assert_ne!(entity.location(), old_location);
204
}
205
206
// regression test for https://github.com/bevyengine/bevy/pull/7805
207
#[test]
208
fn removing_sparse_updates_archetype_row() {
209
#[derive(Component, PartialEq, Debug)]
210
struct Dense(u8);
211
212
#[derive(Component)]
213
#[component(storage = "SparseSet")]
214
struct Sparse;
215
216
let mut world = World::new();
217
let e1 = world.spawn((Dense(0), Sparse)).id();
218
let e2 = world.spawn((Dense(1), Sparse)).id();
219
220
world.entity_mut(e1).remove::<Sparse>();
221
assert_eq!(world.entity(e2).get::<Dense>().unwrap(), &Dense(1));
222
}
223
224
// regression test for https://github.com/bevyengine/bevy/pull/7805
225
#[test]
226
fn removing_dense_updates_table_row() {
227
#[derive(Component, PartialEq, Debug)]
228
struct Dense(u8);
229
230
#[derive(Component)]
231
#[component(storage = "SparseSet")]
232
struct Sparse;
233
234
let mut world = World::new();
235
let e1 = world.spawn((Dense(0), Sparse)).id();
236
let e2 = world.spawn((Dense(1), Sparse)).id();
237
238
world.entity_mut(e1).remove::<Dense>();
239
assert_eq!(world.entity(e2).get::<Dense>().unwrap(), &Dense(1));
240
}
241
242
// Test that calling retain with `()` removes all components.
243
#[test]
244
fn retain_nothing() {
245
#[derive(Component)]
246
struct Marker<const N: usize>;
247
248
let mut world = World::new();
249
let ent = world.spawn((Marker::<1>, Marker::<2>, Marker::<3>)).id();
250
251
world.entity_mut(ent).retain::<()>();
252
assert_eq!(world.entity(ent).archetype().components().len(), 0);
253
}
254
255
// Test removing some components with `retain`, including components not on the entity.
256
#[test]
257
fn retain_some_components() {
258
#[derive(Component)]
259
struct Marker<const N: usize>;
260
261
let mut world = World::new();
262
let ent = world.spawn((Marker::<1>, Marker::<2>, Marker::<3>)).id();
263
264
world.entity_mut(ent).retain::<(Marker<2>, Marker<4>)>();
265
// Check that marker 2 was retained.
266
assert!(world.entity(ent).get::<Marker<2>>().is_some());
267
// Check that only marker 2 was retained.
268
assert_eq!(world.entity(ent).archetype().components().len(), 1);
269
}
270
271
// regression test for https://github.com/bevyengine/bevy/pull/7805
272
#[test]
273
fn inserting_sparse_updates_archetype_row() {
274
#[derive(Component, PartialEq, Debug)]
275
struct Dense(u8);
276
277
#[derive(Component)]
278
#[component(storage = "SparseSet")]
279
struct Sparse;
280
281
let mut world = World::new();
282
let e1 = world.spawn(Dense(0)).id();
283
let e2 = world.spawn(Dense(1)).id();
284
285
world.entity_mut(e1).insert(Sparse);
286
assert_eq!(world.entity(e2).get::<Dense>().unwrap(), &Dense(1));
287
}
288
289
// regression test for https://github.com/bevyengine/bevy/pull/7805
290
#[test]
291
fn inserting_dense_updates_archetype_row() {
292
#[derive(Component, PartialEq, Debug)]
293
struct Dense(u8);
294
295
#[derive(Component)]
296
struct Dense2;
297
298
#[derive(Component)]
299
#[component(storage = "SparseSet")]
300
struct Sparse;
301
302
let mut world = World::new();
303
let e1 = world.spawn(Dense(0)).id();
304
let e2 = world.spawn(Dense(1)).id();
305
306
world.entity_mut(e1).insert(Sparse).remove::<Sparse>();
307
308
// archetype with [e2, e1]
309
// table with [e1, e2]
310
311
world.entity_mut(e2).insert(Dense2);
312
313
assert_eq!(world.entity(e1).get::<Dense>().unwrap(), &Dense(0));
314
}
315
316
#[test]
317
fn inserting_dense_updates_table_row() {
318
#[derive(Component, PartialEq, Debug)]
319
struct Dense(u8);
320
321
#[derive(Component)]
322
struct Dense2;
323
324
#[derive(Component)]
325
#[component(storage = "SparseSet")]
326
struct Sparse;
327
328
let mut world = World::new();
329
let e1 = world.spawn(Dense(0)).id();
330
let e2 = world.spawn(Dense(1)).id();
331
332
world.entity_mut(e1).insert(Sparse).remove::<Sparse>();
333
334
// archetype with [e2, e1]
335
// table with [e1, e2]
336
337
world.entity_mut(e1).insert(Dense2);
338
339
assert_eq!(world.entity(e2).get::<Dense>().unwrap(), &Dense(1));
340
}
341
342
// regression test for https://github.com/bevyengine/bevy/pull/7805
343
#[test]
344
fn despawning_entity_updates_archetype_row() {
345
#[derive(Component, PartialEq, Debug)]
346
struct Dense(u8);
347
348
#[derive(Component)]
349
#[component(storage = "SparseSet")]
350
struct Sparse;
351
352
let mut world = World::new();
353
let e1 = world.spawn(Dense(0)).id();
354
let e2 = world.spawn(Dense(1)).id();
355
356
world.entity_mut(e1).insert(Sparse).remove::<Sparse>();
357
358
// archetype with [e2, e1]
359
// table with [e1, e2]
360
361
world.entity_mut(e2).despawn();
362
363
assert_eq!(world.entity(e1).get::<Dense>().unwrap(), &Dense(0));
364
}
365
366
// regression test for https://github.com/bevyengine/bevy/pull/7805
367
#[test]
368
fn despawning_entity_updates_table_row() {
369
#[derive(Component, PartialEq, Debug)]
370
struct Dense(u8);
371
372
#[derive(Component)]
373
#[component(storage = "SparseSet")]
374
struct Sparse;
375
376
let mut world = World::new();
377
let e1 = world.spawn(Dense(0)).id();
378
let e2 = world.spawn(Dense(1)).id();
379
380
world.entity_mut(e1).insert(Sparse).remove::<Sparse>();
381
382
// archetype with [e2, e1]
383
// table with [e1, e2]
384
385
world.entity_mut(e1).despawn();
386
387
assert_eq!(world.entity(e2).get::<Dense>().unwrap(), &Dense(1));
388
}
389
390
#[test]
391
fn entity_mut_insert_by_id() {
392
let mut world = World::new();
393
let test_component_id = world.register_component::<TestComponent>();
394
395
let mut entity = world.spawn_empty();
396
OwningPtr::make(TestComponent(42), |ptr| {
397
// SAFETY: `ptr` matches the component id
398
unsafe { entity.insert_by_id(test_component_id, ptr) };
399
});
400
401
let components: Vec<_> = world.query::<&TestComponent>().iter(&world).collect();
402
403
assert_eq!(components, vec![&TestComponent(42)]);
404
405
// Compare with `insert_bundle_by_id`
406
407
let mut entity = world.spawn_empty();
408
OwningPtr::make(TestComponent(84), |ptr| {
409
// SAFETY: `ptr` matches the component id
410
unsafe { entity.insert_by_ids(&[test_component_id], vec![ptr].into_iter()) };
411
});
412
413
let components: Vec<_> = world.query::<&TestComponent>().iter(&world).collect();
414
415
assert_eq!(components, vec![&TestComponent(42), &TestComponent(84)]);
416
}
417
418
#[test]
419
fn entity_mut_insert_bundle_by_id() {
420
let mut world = World::new();
421
let test_component_id = world.register_component::<TestComponent>();
422
let test_component_2_id = world.register_component::<TestComponent2>();
423
424
let component_ids = [test_component_id, test_component_2_id];
425
let test_component_value = TestComponent(42);
426
let test_component_2_value = TestComponent2(84);
427
428
let mut entity = world.spawn_empty();
429
OwningPtr::make(test_component_value, |ptr1| {
430
OwningPtr::make(test_component_2_value, |ptr2| {
431
// SAFETY: `ptr1` and `ptr2` match the component ids
432
unsafe { entity.insert_by_ids(&component_ids, vec![ptr1, ptr2].into_iter()) };
433
});
434
});
435
436
let dynamic_components: Vec<_> = world
437
.query::<(&TestComponent, &TestComponent2)>()
438
.iter(&world)
439
.collect();
440
441
assert_eq!(
442
dynamic_components,
443
vec![(&TestComponent(42), &TestComponent2(84))]
444
);
445
446
// Compare with `World` generated using static type equivalents
447
let mut static_world = World::new();
448
449
static_world.spawn((test_component_value, test_component_2_value));
450
let static_components: Vec<_> = static_world
451
.query::<(&TestComponent, &TestComponent2)>()
452
.iter(&static_world)
453
.collect();
454
455
assert_eq!(dynamic_components, static_components);
456
}
457
458
#[test]
459
fn entity_mut_remove_by_id() {
460
let mut world = World::new();
461
let test_component_id = world.register_component::<TestComponent>();
462
463
let mut entity = world.spawn(TestComponent(42));
464
entity.remove_by_id(test_component_id);
465
466
let components: Vec<_> = world.query::<&TestComponent>().iter(&world).collect();
467
468
assert_eq!(components, vec![] as Vec<&TestComponent>);
469
470
// remove non-existent component does not panic
471
world.spawn_empty().remove_by_id(test_component_id);
472
}
473
474
/// Tests that components can be accessed through an `EntityRefExcept`.
475
#[test]
476
fn entity_ref_except() {
477
let mut world = World::new();
478
world.register_component::<TestComponent>();
479
world.register_component::<TestComponent2>();
480
481
world.spawn((TestComponent(0), TestComponent2(0), Marker));
482
483
let mut query = world.query_filtered::<EntityRefExcept<TestComponent>, With<Marker>>();
484
485
let mut found = false;
486
for entity_ref in query.iter_mut(&mut world) {
487
found = true;
488
assert!(entity_ref.get::<TestComponent>().is_none());
489
assert!(entity_ref.get_ref::<TestComponent>().is_none());
490
assert!(matches!(
491
entity_ref.get::<TestComponent2>(),
492
Some(TestComponent2(0))
493
));
494
}
495
496
assert!(found);
497
}
498
499
// Test that a single query can't both contain a mutable reference to a
500
// component C and an `EntityRefExcept` that doesn't include C among its
501
// exclusions.
502
#[test]
503
#[should_panic]
504
fn entity_ref_except_conflicts_with_self() {
505
let mut world = World::new();
506
world.spawn(TestComponent(0)).insert(TestComponent2(0));
507
508
// This should panic, because we have a mutable borrow on
509
// `TestComponent` but have a simultaneous indirect immutable borrow on
510
// that component via `EntityRefExcept`.
511
world.run_system_once(system).unwrap();
512
513
fn system(_: Query<(&mut TestComponent, EntityRefExcept<TestComponent2>)>) {}
514
}
515
516
// Test that an `EntityRefExcept` that doesn't include a component C among
517
// its exclusions can't coexist with a mutable query for that component.
518
#[test]
519
#[should_panic]
520
fn entity_ref_except_conflicts_with_other() {
521
let mut world = World::new();
522
world.spawn(TestComponent(0)).insert(TestComponent2(0));
523
524
// This should panic, because we have a mutable borrow on
525
// `TestComponent` but have a simultaneous indirect immutable borrow on
526
// that component via `EntityRefExcept`.
527
world.run_system_once(system).unwrap();
528
529
fn system(_: Query<&mut TestComponent>, _: Query<EntityRefExcept<TestComponent2>>) {}
530
}
531
532
// Test that an `EntityRefExcept` with an exception for some component C can
533
// coexist with a query for that component C.
534
#[test]
535
fn entity_ref_except_doesnt_conflict() {
536
let mut world = World::new();
537
world.spawn((TestComponent(0), TestComponent2(0), Marker));
538
539
world.run_system_once(system).unwrap();
540
541
fn system(
542
_: Query<&mut TestComponent, With<Marker>>,
543
query: Query<EntityRefExcept<TestComponent>, With<Marker>>,
544
) {
545
for entity_ref in query.iter() {
546
assert!(matches!(
547
entity_ref.get::<TestComponent2>(),
548
Some(TestComponent2(0))
549
));
550
}
551
}
552
}
553
554
/// Tests that components can be mutably accessed through an
555
/// `EntityMutExcept`.
556
#[test]
557
fn entity_mut_except() {
558
let mut world = World::new();
559
world.spawn((TestComponent(0), TestComponent2(0), Marker));
560
561
let mut query = world.query_filtered::<EntityMutExcept<TestComponent>, With<Marker>>();
562
563
let mut found = false;
564
for mut entity_mut in query.iter_mut(&mut world) {
565
found = true;
566
assert!(entity_mut.get::<TestComponent>().is_none());
567
assert!(entity_mut.get_ref::<TestComponent>().is_none());
568
assert!(entity_mut.get_mut::<TestComponent>().is_none());
569
assert!(matches!(
570
entity_mut.get::<TestComponent2>(),
571
Some(TestComponent2(0))
572
));
573
}
574
575
assert!(found);
576
}
577
578
// Test that a single query can't both contain a mutable reference to a
579
// component C and an `EntityMutExcept` that doesn't include C among its
580
// exclusions.
581
#[test]
582
#[should_panic]
583
fn entity_mut_except_conflicts_with_self() {
584
let mut world = World::new();
585
world.spawn(TestComponent(0)).insert(TestComponent2(0));
586
587
// This should panic, because we have a mutable borrow on
588
// `TestComponent` but have a simultaneous indirect immutable borrow on
589
// that component via `EntityRefExcept`.
590
world.run_system_once(system).unwrap();
591
592
fn system(_: Query<(&mut TestComponent, EntityMutExcept<TestComponent2>)>) {}
593
}
594
595
// Test that an `EntityMutExcept` that doesn't include a component C among
596
// its exclusions can't coexist with a query for that component.
597
#[test]
598
#[should_panic]
599
fn entity_mut_except_conflicts_with_other() {
600
let mut world = World::new();
601
world.spawn(TestComponent(0)).insert(TestComponent2(0));
602
603
// This should panic, because we have a mutable borrow on
604
// `TestComponent` but have a simultaneous indirect immutable borrow on
605
// that component via `EntityRefExcept`.
606
world.run_system_once(system).unwrap();
607
608
fn system(_: Query<&mut TestComponent>, mut query: Query<EntityMutExcept<TestComponent2>>) {
609
for mut entity_mut in query.iter_mut() {
610
assert!(entity_mut
611
.get_mut::<TestComponent2>()
612
.is_some_and(|component| component.0 == 0));
613
}
614
}
615
}
616
617
// Test that an `EntityMutExcept` with an exception for some component C can
618
// coexist with a query for that component C.
619
#[test]
620
fn entity_mut_except_doesnt_conflict() {
621
let mut world = World::new();
622
world.spawn((TestComponent(0), TestComponent2(0), Marker));
623
624
world.run_system_once(system).unwrap();
625
626
fn system(
627
_: Query<&mut TestComponent, With<Marker>>,
628
mut query: Query<EntityMutExcept<TestComponent>, With<Marker>>,
629
) {
630
for mut entity_mut in query.iter_mut() {
631
assert!(entity_mut
632
.get_mut::<TestComponent2>()
633
.is_some_and(|component| component.0 == 0));
634
}
635
}
636
}
637
638
#[test]
639
fn entity_mut_except_registers_components() {
640
// Checks for a bug where `EntityMutExcept` would not register the component and
641
// would therefore not include an exception, causing it to conflict with the later query.
642
fn system1(_query: Query<EntityMutExcept<TestComponent>>, _: Query<&mut TestComponent>) {}
643
let mut world = World::new();
644
world.run_system_once(system1).unwrap();
645
646
fn system2(_: Query<&mut TestComponent>, _query: Query<EntityMutExcept<TestComponent>>) {}
647
let mut world = World::new();
648
world.run_system_once(system2).unwrap();
649
}
650
651
#[derive(Component)]
652
struct A;
653
654
#[test]
655
fn disjoint_access() {
656
fn disjoint_readonly(_: Query<EntityMut, With<A>>, _: Query<EntityRef, Without<A>>) {}
657
658
fn disjoint_mutable(_: Query<EntityMut, With<A>>, _: Query<EntityMut, Without<A>>) {}
659
660
assert_is_system(disjoint_readonly);
661
assert_is_system(disjoint_mutable);
662
}
663
664
#[test]
665
fn ref_compatible() {
666
fn borrow_system(_: Query<(EntityRef, &A)>, _: Query<&A>) {}
667
668
assert_is_system(borrow_system);
669
}
670
671
#[test]
672
fn ref_compatible_with_resource() {
673
fn borrow_system(_: Query<EntityRef>, _: Res<R>) {}
674
675
assert_is_system(borrow_system);
676
}
677
678
#[test]
679
#[should_panic]
680
fn ref_incompatible_with_resource_mut() {
681
fn borrow_system(_: Query<EntityRef>, _: ResMut<R>) {}
682
683
assert_is_system(borrow_system);
684
}
685
686
#[test]
687
fn ref_compatible_with_resource_mut() {
688
fn borrow_system(_: Query<EntityRef, Without<IsResource>>, _: ResMut<R>) {}
689
690
assert_is_system(borrow_system);
691
}
692
693
#[test]
694
#[should_panic]
695
fn ref_incompatible_with_mutable_component() {
696
fn incompatible_system(_: Query<(EntityRef, &mut A)>) {}
697
698
assert_is_system(incompatible_system);
699
}
700
701
#[test]
702
#[should_panic]
703
fn ref_incompatible_with_mutable_query() {
704
fn incompatible_system(_: Query<EntityRef>, _: Query<&mut A>) {}
705
706
assert_is_system(incompatible_system);
707
}
708
709
#[test]
710
fn mut_compatible_with_entity() {
711
fn borrow_mut_system(_: Query<(Entity, EntityMut)>) {}
712
713
assert_is_system(borrow_mut_system);
714
}
715
716
#[test]
717
#[should_panic]
718
fn mut_incompatible_with_resource() {
719
fn borrow_mut_system(_: Res<R>, _: Query<EntityMut>) {}
720
721
assert_is_system(borrow_mut_system);
722
}
723
724
#[test]
725
#[should_panic]
726
fn mut_incompatible_with_resource_mut() {
727
fn borrow_mut_system(_: ResMut<R>, _: Query<EntityMut>) {}
728
729
assert_is_system(borrow_mut_system);
730
}
731
732
#[test]
733
fn mut_compatible_with_resource() {
734
fn borrow_mut_system(_: Res<R>, _: Query<EntityMut, Without<IsResource>>) {}
735
736
assert_is_system(borrow_mut_system);
737
}
738
739
#[test]
740
fn mut_compatible_with_resource_mut() {
741
fn borrow_mut_system(_: ResMut<R>, _: Query<EntityMut, Without<IsResource>>) {}
742
743
assert_is_system(borrow_mut_system);
744
}
745
746
#[test]
747
#[should_panic]
748
fn mut_incompatible_with_read_only_component() {
749
fn incompatible_system(_: Query<(EntityMut, &A)>) {}
750
751
assert_is_system(incompatible_system);
752
}
753
754
#[test]
755
#[should_panic]
756
fn mut_incompatible_with_mutable_component() {
757
fn incompatible_system(_: Query<(EntityMut, &mut A)>) {}
758
759
assert_is_system(incompatible_system);
760
}
761
762
#[test]
763
#[should_panic]
764
fn mut_incompatible_with_read_only_query() {
765
fn incompatible_system(_: Query<EntityMut>, _: Query<&A>) {}
766
767
assert_is_system(incompatible_system);
768
}
769
770
#[test]
771
#[should_panic]
772
fn mut_incompatible_with_mutable_query() {
773
fn incompatible_system(_: Query<EntityMut>, _: Query<&mut A>) {}
774
775
assert_is_system(incompatible_system);
776
}
777
778
#[test]
779
fn filtered_entity_ref_normal() {
780
let mut world = World::new();
781
let a_id = world.register_component::<A>();
782
783
let e: FilteredEntityRef = world.spawn(A).into();
784
785
assert!(e.get::<A>().is_some());
786
assert!(e.get_ref::<A>().is_some());
787
assert!(e.get_change_ticks::<A>().is_some());
788
assert!(e.get_by_id(a_id).is_some());
789
assert!(e.get_change_ticks_by_id(a_id).is_some());
790
}
791
792
#[test]
793
fn filtered_entity_ref_missing() {
794
let mut world = World::new();
795
let a_id = world.register_component::<A>();
796
797
let e: FilteredEntityRef = world.spawn(()).into();
798
799
assert!(e.get::<A>().is_none());
800
assert!(e.get_ref::<A>().is_none());
801
assert!(e.get_change_ticks::<A>().is_none());
802
assert!(e.get_by_id(a_id).is_none());
803
assert!(e.get_change_ticks_by_id(a_id).is_none());
804
}
805
806
#[test]
807
fn filtered_entity_mut_normal() {
808
let mut world = World::new();
809
let a_id = world.register_component::<A>();
810
811
let mut e: FilteredEntityMut = world.spawn(A).into();
812
813
assert!(e.get::<A>().is_some());
814
assert!(e.get_ref::<A>().is_some());
815
assert!(e.get_mut::<A>().is_some());
816
assert!(e.get_change_ticks::<A>().is_some());
817
assert!(e.get_by_id(a_id).is_some());
818
assert!(e.get_mut_by_id(a_id).is_some());
819
assert!(e.get_change_ticks_by_id(a_id).is_some());
820
}
821
822
#[test]
823
fn filtered_entity_mut_missing() {
824
let mut world = World::new();
825
let a_id = world.register_component::<A>();
826
827
let mut e: FilteredEntityMut = world.spawn(()).into();
828
829
assert!(e.get::<A>().is_none());
830
assert!(e.get_ref::<A>().is_none());
831
assert!(e.get_mut::<A>().is_none());
832
assert!(e.get_change_ticks::<A>().is_none());
833
assert!(e.get_by_id(a_id).is_none());
834
assert!(e.get_mut_by_id(a_id).is_none());
835
assert!(e.get_change_ticks_by_id(a_id).is_none());
836
}
837
838
#[derive(Component, PartialEq, Eq, Debug)]
839
struct X(usize);
840
841
#[derive(Component, PartialEq, Eq, Debug)]
842
struct Y(usize);
843
844
#[test]
845
fn get_components() {
846
let mut world = World::default();
847
let e1 = world.spawn((X(7), Y(10))).id();
848
let e2 = world.spawn(X(8)).id();
849
let e3 = world.spawn_empty().id();
850
851
assert_eq!(
852
Ok((&X(7), &Y(10))),
853
world.entity(e1).get_components::<(&X, &Y)>()
854
);
855
assert_eq!(
856
Err(QueryAccessError::EntityDoesNotMatch),
857
world.entity(e2).get_components::<(&X, &Y)>()
858
);
859
assert_eq!(
860
Err(QueryAccessError::EntityDoesNotMatch),
861
world.entity(e3).get_components::<(&X, &Y)>()
862
);
863
}
864
865
#[test]
866
fn get_components_mut() {
867
let mut world = World::default();
868
let e1 = world.spawn((X(7), Y(10))).id();
869
870
let mut entity_mut_1 = world.entity_mut(e1);
871
let Ok((mut x, mut y)) = entity_mut_1.get_components_mut::<(&mut X, &mut Y)>() else {
872
panic!("could not get components");
873
};
874
x.0 += 1;
875
y.0 += 1;
876
877
assert_eq!(
878
Ok((&X(8), &Y(11))),
879
world.entity(e1).get_components::<(&X, &Y)>()
880
);
881
}
882
883
#[test]
884
fn get_by_id_array() {
885
let mut world = World::default();
886
let e1 = world.spawn((X(7), Y(10))).id();
887
let e2 = world.spawn(X(8)).id();
888
let e3 = world.spawn_empty().id();
889
890
let x_id = world.register_component::<X>();
891
let y_id = world.register_component::<Y>();
892
893
assert_eq!(
894
Ok((&X(7), &Y(10))),
895
world
896
.entity(e1)
897
.get_by_id([x_id, y_id])
898
.map(|[x_ptr, y_ptr]| {
899
// SAFETY: components match the id they were fetched with
900
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
901
})
902
);
903
assert_eq!(
904
Err(EntityComponentError::MissingComponent(y_id)),
905
world
906
.entity(e2)
907
.get_by_id([x_id, y_id])
908
.map(|[x_ptr, y_ptr]| {
909
// SAFETY: components match the id they were fetched with
910
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
911
})
912
);
913
assert_eq!(
914
Err(EntityComponentError::MissingComponent(x_id)),
915
world
916
.entity(e3)
917
.get_by_id([x_id, y_id])
918
.map(|[x_ptr, y_ptr]| {
919
// SAFETY: components match the id they were fetched with
920
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
921
})
922
);
923
}
924
925
#[test]
926
fn get_by_id_vec() {
927
let mut world = World::default();
928
let e1 = world.spawn((X(7), Y(10))).id();
929
let e2 = world.spawn(X(8)).id();
930
let e3 = world.spawn_empty().id();
931
932
let x_id = world.register_component::<X>();
933
let y_id = world.register_component::<Y>();
934
935
assert_eq!(
936
Ok((&X(7), &Y(10))),
937
world
938
.entity(e1)
939
.get_by_id(&[x_id, y_id] as &[ComponentId])
940
.map(|ptrs| {
941
let Ok([x_ptr, y_ptr]): Result<[Ptr; 2], _> = ptrs.try_into() else {
942
panic!("get_by_id(slice) didn't return 2 elements")
943
};
944
945
// SAFETY: components match the id they were fetched with
946
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
947
})
948
);
949
assert_eq!(
950
Err(EntityComponentError::MissingComponent(y_id)),
951
world
952
.entity(e2)
953
.get_by_id(&[x_id, y_id] as &[ComponentId])
954
.map(|ptrs| {
955
let Ok([x_ptr, y_ptr]): Result<[Ptr; 2], _> = ptrs.try_into() else {
956
panic!("get_by_id(slice) didn't return 2 elements")
957
};
958
959
// SAFETY: components match the id they were fetched with
960
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
961
})
962
);
963
assert_eq!(
964
Err(EntityComponentError::MissingComponent(x_id)),
965
world
966
.entity(e3)
967
.get_by_id(&[x_id, y_id] as &[ComponentId])
968
.map(|ptrs| {
969
let Ok([x_ptr, y_ptr]): Result<[Ptr; 2], _> = ptrs.try_into() else {
970
panic!("get_by_id(slice) didn't return 2 elements")
971
};
972
973
// SAFETY: components match the id they were fetched with
974
(unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() })
975
})
976
);
977
}
978
979
#[test]
980
fn get_mut_by_id_array() {
981
let mut world = World::default();
982
let e1 = world.spawn((X(7), Y(10))).id();
983
let e2 = world.spawn(X(8)).id();
984
let e3 = world.spawn_empty().id();
985
986
let x_id = world.register_component::<X>();
987
let y_id = world.register_component::<Y>();
988
989
assert_eq!(
990
Ok((&mut X(7), &mut Y(10))),
991
world
992
.entity_mut(e1)
993
.get_mut_by_id([x_id, y_id])
994
.map(|[x_ptr, y_ptr]| {
995
// SAFETY: components match the id they were fetched with
996
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
997
y_ptr.into_inner().deref_mut::<Y>()
998
})
999
})
1000
);
1001
assert_eq!(
1002
Err(EntityComponentError::MissingComponent(y_id)),
1003
world
1004
.entity_mut(e2)
1005
.get_mut_by_id([x_id, y_id])
1006
.map(|[x_ptr, y_ptr]| {
1007
// SAFETY: components match the id they were fetched with
1008
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
1009
y_ptr.into_inner().deref_mut::<Y>()
1010
})
1011
})
1012
);
1013
assert_eq!(
1014
Err(EntityComponentError::MissingComponent(x_id)),
1015
world
1016
.entity_mut(e3)
1017
.get_mut_by_id([x_id, y_id])
1018
.map(|[x_ptr, y_ptr]| {
1019
// SAFETY: components match the id they were fetched with
1020
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
1021
y_ptr.into_inner().deref_mut::<Y>()
1022
})
1023
})
1024
);
1025
1026
assert_eq!(
1027
Err(EntityComponentError::AliasedMutability(x_id)),
1028
world
1029
.entity_mut(e1)
1030
.get_mut_by_id([x_id, x_id])
1031
.map(|_| { unreachable!() })
1032
);
1033
assert_eq!(
1034
Err(EntityComponentError::AliasedMutability(x_id)),
1035
world
1036
.entity_mut(e3)
1037
.get_mut_by_id([x_id, x_id])
1038
.map(|_| { unreachable!() })
1039
);
1040
}
1041
1042
#[test]
1043
fn get_mut_by_id_vec() {
1044
let mut world = World::default();
1045
let e1 = world.spawn((X(7), Y(10))).id();
1046
let e2 = world.spawn(X(8)).id();
1047
let e3 = world.spawn_empty().id();
1048
1049
let x_id = world.register_component::<X>();
1050
let y_id = world.register_component::<Y>();
1051
1052
assert_eq!(
1053
Ok((&mut X(7), &mut Y(10))),
1054
world
1055
.entity_mut(e1)
1056
.get_mut_by_id(&[x_id, y_id] as &[ComponentId])
1057
.map(|ptrs| {
1058
let Ok([x_ptr, y_ptr]): Result<[MutUntyped; 2], _> = ptrs.try_into() else {
1059
panic!("get_mut_by_id(slice) didn't return 2 elements")
1060
};
1061
1062
// SAFETY: components match the id they were fetched with
1063
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
1064
y_ptr.into_inner().deref_mut::<Y>()
1065
})
1066
})
1067
);
1068
assert_eq!(
1069
Err(EntityComponentError::MissingComponent(y_id)),
1070
world
1071
.entity_mut(e2)
1072
.get_mut_by_id(&[x_id, y_id] as &[ComponentId])
1073
.map(|ptrs| {
1074
let Ok([x_ptr, y_ptr]): Result<[MutUntyped; 2], _> = ptrs.try_into() else {
1075
panic!("get_mut_by_id(slice) didn't return 2 elements")
1076
};
1077
1078
// SAFETY: components match the id they were fetched with
1079
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
1080
y_ptr.into_inner().deref_mut::<Y>()
1081
})
1082
})
1083
);
1084
assert_eq!(
1085
Err(EntityComponentError::MissingComponent(x_id)),
1086
world
1087
.entity_mut(e3)
1088
.get_mut_by_id(&[x_id, y_id] as &[ComponentId])
1089
.map(|ptrs| {
1090
let Ok([x_ptr, y_ptr]): Result<[MutUntyped; 2], _> = ptrs.try_into() else {
1091
panic!("get_mut_by_id(slice) didn't return 2 elements")
1092
};
1093
1094
// SAFETY: components match the id they were fetched with
1095
(unsafe { x_ptr.into_inner().deref_mut::<X>() }, unsafe {
1096
y_ptr.into_inner().deref_mut::<Y>()
1097
})
1098
})
1099
);
1100
1101
assert_eq!(
1102
Err(EntityComponentError::AliasedMutability(x_id)),
1103
world
1104
.entity_mut(e1)
1105
.get_mut_by_id(&[x_id, x_id])
1106
.map(|_| { unreachable!() })
1107
);
1108
assert_eq!(
1109
Err(EntityComponentError::AliasedMutability(x_id)),
1110
world
1111
.entity_mut(e3)
1112
.get_mut_by_id(&[x_id, x_id])
1113
.map(|_| { unreachable!() })
1114
);
1115
}
1116
1117
#[test]
1118
fn get_mut_by_id_unchecked() {
1119
let mut world = World::default();
1120
let e1 = world.spawn((X(7), Y(10))).id();
1121
let x_id = world.register_component::<X>();
1122
let y_id = world.register_component::<Y>();
1123
1124
let e1_mut = &world.get_entity_mut([e1]).unwrap()[0];
1125
// SAFETY: The entity e1 contains component X.
1126
let x_ptr = unsafe { e1_mut.get_mut_by_id_unchecked(x_id) }.unwrap();
1127
// SAFETY: The entity e1 contains component Y, with components X and Y being mutually independent.
1128
let y_ptr = unsafe { e1_mut.get_mut_by_id_unchecked(y_id) }.unwrap();
1129
1130
// SAFETY: components match the id they were fetched with
1131
let x_component = unsafe { x_ptr.into_inner().deref_mut::<X>() };
1132
x_component.0 += 1;
1133
// SAFETY: components match the id they were fetched with
1134
let y_component = unsafe { y_ptr.into_inner().deref_mut::<Y>() };
1135
y_component.0 -= 1;
1136
1137
assert_eq!((&mut X(8), &mut Y(9)), (x_component, y_component));
1138
}
1139
1140
#[derive(EntityEvent)]
1141
struct TestEvent(Entity);
1142
1143
#[test]
1144
fn adding_observer_updates_location() {
1145
let mut world = World::new();
1146
let entity = world
1147
.spawn_empty()
1148
.observe(|event: On<TestEvent>, mut commands: Commands| {
1149
commands
1150
.entity(event.event_target())
1151
.insert(TestComponent(0));
1152
})
1153
.id();
1154
1155
// this should not be needed, but is currently required to tease out the bug
1156
world.flush();
1157
1158
let mut a = world.entity_mut(entity);
1159
// SAFETY: this _intentionally_ doesn't update the location, to ensure that we're actually testing
1160
// that observe() updates location
1161
unsafe { a.world_mut().trigger(TestEvent(entity)) }
1162
a.observe(|_: On<TestEvent>| {}); // this flushes commands implicitly by spawning
1163
let location = a.location();
1164
assert_eq!(world.entities().get(entity).unwrap(), Some(location));
1165
}
1166
1167
#[test]
1168
#[should_panic]
1169
fn location_on_despawned_entity_panics() {
1170
let mut world = World::new();
1171
world.add_observer(|add: On<Add, TestComponent>, mut commands: Commands| {
1172
commands.entity(add.entity).despawn();
1173
});
1174
let entity = world.spawn_empty().id();
1175
let mut a = world.entity_mut(entity);
1176
a.insert(TestComponent(0));
1177
a.location();
1178
}
1179
1180
#[derive(Resource)]
1181
struct TestFlush(usize);
1182
1183
fn count_flush(world: &mut World) {
1184
world.resource_mut::<TestFlush>().0 += 1;
1185
}
1186
1187
#[test]
1188
fn archetype_modifications_trigger_flush() {
1189
let mut world = World::new();
1190
world.insert_resource(TestFlush(0));
1191
world.add_observer(|_: On<Add, TestComponent>, mut commands: Commands| {
1192
commands.queue(count_flush);
1193
});
1194
world.add_observer(|_: On<Remove, TestComponent>, mut commands: Commands| {
1195
commands.queue(count_flush);
1196
});
1197
1198
// Spawning an empty should not flush.
1199
world.commands().queue(count_flush);
1200
let entity = world.spawn_empty().id();
1201
assert_eq!(world.resource::<TestFlush>().0, 0);
1202
1203
world.commands().queue(count_flush);
1204
world.flush_commands();
1205
1206
let mut a = world.entity_mut(entity);
1207
assert_eq!(a.world().resource::<TestFlush>().0, 2);
1208
a.insert(TestComponent(0));
1209
assert_eq!(a.world().resource::<TestFlush>().0, 3);
1210
a.remove::<TestComponent>();
1211
assert_eq!(a.world().resource::<TestFlush>().0, 4);
1212
a.insert(TestComponent(0));
1213
assert_eq!(a.world().resource::<TestFlush>().0, 5);
1214
let _ = a.take::<TestComponent>();
1215
assert_eq!(a.world().resource::<TestFlush>().0, 6);
1216
a.insert(TestComponent(0));
1217
assert_eq!(a.world().resource::<TestFlush>().0, 7);
1218
a.retain::<()>();
1219
assert_eq!(a.world().resource::<TestFlush>().0, 8);
1220
a.insert(TestComponent(0));
1221
assert_eq!(a.world().resource::<TestFlush>().0, 9);
1222
a.clear();
1223
assert_eq!(a.world().resource::<TestFlush>().0, 10);
1224
a.insert(TestComponent(0));
1225
assert_eq!(a.world().resource::<TestFlush>().0, 11);
1226
a.despawn();
1227
assert_eq!(world.resource::<TestFlush>().0, 12);
1228
}
1229
1230
#[derive(Resource)]
1231
struct TestVec(Vec<&'static str>);
1232
1233
#[derive(Component)]
1234
#[component(on_add = ord_a_hook_on_add, on_insert = ord_a_hook_on_insert, on_replace = ord_a_hook_on_replace, on_remove = ord_a_hook_on_remove)]
1235
struct OrdA;
1236
1237
fn ord_a_hook_on_add(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
1238
world.resource_mut::<TestVec>().0.push("OrdA hook on_add");
1239
world.commands().entity(entity).insert(OrdB);
1240
}
1241
1242
fn ord_a_hook_on_insert(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
1243
world
1244
.resource_mut::<TestVec>()
1245
.0
1246
.push("OrdA hook on_insert");
1247
world.commands().entity(entity).remove::<OrdA>();
1248
world.commands().entity(entity).remove::<OrdB>();
1249
}
1250
1251
fn ord_a_hook_on_replace(mut world: DeferredWorld, _: HookContext) {
1252
world
1253
.resource_mut::<TestVec>()
1254
.0
1255
.push("OrdA hook on_replace");
1256
}
1257
1258
fn ord_a_hook_on_remove(mut world: DeferredWorld, _: HookContext) {
1259
world
1260
.resource_mut::<TestVec>()
1261
.0
1262
.push("OrdA hook on_remove");
1263
}
1264
1265
fn ord_a_observer_on_add(_event: On<Add, OrdA>, mut res: ResMut<TestVec>) {
1266
res.0.push("OrdA observer on_add");
1267
}
1268
1269
fn ord_a_observer_on_insert(_event: On<Insert, OrdA>, mut res: ResMut<TestVec>) {
1270
res.0.push("OrdA observer on_insert");
1271
}
1272
1273
fn ord_a_observer_on_replace(_event: On<Replace, OrdA>, mut res: ResMut<TestVec>) {
1274
res.0.push("OrdA observer on_replace");
1275
}
1276
1277
fn ord_a_observer_on_remove(_event: On<Remove, OrdA>, mut res: ResMut<TestVec>) {
1278
res.0.push("OrdA observer on_remove");
1279
}
1280
1281
#[derive(Component)]
1282
#[component(on_add = ord_b_hook_on_add, on_insert = ord_b_hook_on_insert, on_replace = ord_b_hook_on_replace, on_remove = ord_b_hook_on_remove)]
1283
struct OrdB;
1284
1285
fn ord_b_hook_on_add(mut world: DeferredWorld, _: HookContext) {
1286
world.resource_mut::<TestVec>().0.push("OrdB hook on_add");
1287
world.commands().queue(|world: &mut World| {
1288
world
1289
.resource_mut::<TestVec>()
1290
.0
1291
.push("OrdB command on_add");
1292
});
1293
}
1294
1295
fn ord_b_hook_on_insert(mut world: DeferredWorld, _: HookContext) {
1296
world
1297
.resource_mut::<TestVec>()
1298
.0
1299
.push("OrdB hook on_insert");
1300
}
1301
1302
fn ord_b_hook_on_replace(mut world: DeferredWorld, _: HookContext) {
1303
world
1304
.resource_mut::<TestVec>()
1305
.0
1306
.push("OrdB hook on_replace");
1307
}
1308
1309
fn ord_b_hook_on_remove(mut world: DeferredWorld, _: HookContext) {
1310
world
1311
.resource_mut::<TestVec>()
1312
.0
1313
.push("OrdB hook on_remove");
1314
}
1315
1316
fn ord_b_observer_on_add(_event: On<Add, OrdB>, mut res: ResMut<TestVec>) {
1317
res.0.push("OrdB observer on_add");
1318
}
1319
1320
fn ord_b_observer_on_insert(_event: On<Insert, OrdB>, mut res: ResMut<TestVec>) {
1321
res.0.push("OrdB observer on_insert");
1322
}
1323
1324
fn ord_b_observer_on_replace(_event: On<Replace, OrdB>, mut res: ResMut<TestVec>) {
1325
res.0.push("OrdB observer on_replace");
1326
}
1327
1328
fn ord_b_observer_on_remove(_event: On<Remove, OrdB>, mut res: ResMut<TestVec>) {
1329
res.0.push("OrdB observer on_remove");
1330
}
1331
1332
#[test]
1333
fn command_ordering_is_correct() {
1334
let mut world = World::new();
1335
world.insert_resource(TestVec(Vec::new()));
1336
world.add_observer(ord_a_observer_on_add);
1337
world.add_observer(ord_a_observer_on_insert);
1338
world.add_observer(ord_a_observer_on_replace);
1339
world.add_observer(ord_a_observer_on_remove);
1340
world.add_observer(ord_b_observer_on_add);
1341
world.add_observer(ord_b_observer_on_insert);
1342
world.add_observer(ord_b_observer_on_replace);
1343
world.add_observer(ord_b_observer_on_remove);
1344
let _entity = world.spawn(OrdA).id();
1345
let expected = [
1346
"OrdA hook on_add", // adds command to insert OrdB
1347
"OrdA observer on_add",
1348
"OrdA hook on_insert", // adds command to despawn entity
1349
"OrdA observer on_insert",
1350
"OrdB hook on_add", // adds command to just add to this log
1351
"OrdB observer on_add",
1352
"OrdB hook on_insert",
1353
"OrdB observer on_insert",
1354
"OrdB command on_add", // command added by OrdB hook on_add, needs to run before despawn command
1355
"OrdA observer on_replace", // start of despawn
1356
"OrdA hook on_replace",
1357
"OrdA observer on_remove",
1358
"OrdA hook on_remove",
1359
"OrdB observer on_replace",
1360
"OrdB hook on_replace",
1361
"OrdB observer on_remove",
1362
"OrdB hook on_remove",
1363
];
1364
world.flush();
1365
assert_eq!(world.resource_mut::<TestVec>().0.as_slice(), &expected[..]);
1366
}
1367
1368
#[test]
1369
fn entity_world_mut_clone_and_move_components() {
1370
#[derive(Component, Clone, PartialEq, Debug)]
1371
struct A;
1372
1373
#[derive(Component, Clone, PartialEq, Debug)]
1374
struct B;
1375
1376
#[derive(Component, Clone, PartialEq, Debug)]
1377
struct C(u32);
1378
1379
let mut world = World::new();
1380
let entity_a = world.spawn((A, B, C(5))).id();
1381
let entity_b = world.spawn((A, C(4))).id();
1382
1383
world.entity_mut(entity_a).clone_components::<B>(entity_b);
1384
assert_eq!(world.entity(entity_a).get::<B>(), Some(&B));
1385
assert_eq!(world.entity(entity_b).get::<B>(), Some(&B));
1386
1387
world.entity_mut(entity_a).move_components::<C>(entity_b);
1388
assert_eq!(world.entity(entity_a).get::<C>(), None);
1389
assert_eq!(world.entity(entity_b).get::<C>(), Some(&C(5)));
1390
1391
assert_eq!(world.entity(entity_a).get::<A>(), Some(&A));
1392
assert_eq!(world.entity(entity_b).get::<A>(), Some(&A));
1393
}
1394
1395
#[test]
1396
fn entity_world_mut_clone_with_move_and_require() {
1397
#[derive(Component, Clone, PartialEq, Debug)]
1398
#[require(B(3))]
1399
struct A;
1400
1401
#[derive(Component, Clone, PartialEq, Debug, Default)]
1402
#[require(C(3))]
1403
struct B(u32);
1404
1405
#[derive(Component, Clone, PartialEq, Debug, Default)]
1406
#[require(D)]
1407
struct C(u32);
1408
1409
#[derive(Component, Clone, PartialEq, Debug, Default)]
1410
struct D;
1411
1412
let mut world = World::new();
1413
let entity_a = world.spawn((A, B(5))).id();
1414
let entity_b = world.spawn_empty().id();
1415
1416
world
1417
.entity_mut(entity_a)
1418
.clone_with_opt_in(entity_b, |builder| {
1419
builder
1420
.move_components(true)
1421
.allow::<C>()
1422
.without_required_components(|builder| {
1423
builder.allow::<A>();
1424
});
1425
});
1426
1427
assert_eq!(world.entity(entity_a).get::<A>(), None);
1428
assert_eq!(world.entity(entity_b).get::<A>(), Some(&A));
1429
1430
assert_eq!(world.entity(entity_a).get::<B>(), Some(&B(5)));
1431
assert_eq!(world.entity(entity_b).get::<B>(), Some(&B(3)));
1432
1433
assert_eq!(world.entity(entity_a).get::<C>(), None);
1434
assert_eq!(world.entity(entity_b).get::<C>(), Some(&C(3)));
1435
1436
assert_eq!(world.entity(entity_a).get::<D>(), None);
1437
assert_eq!(world.entity(entity_b).get::<D>(), Some(&D));
1438
}
1439
1440
#[test]
1441
fn command_despawns_dont_invalidate_entity_world_muts() {
1442
let mut world = World::new();
1443
1444
let mut entity = world.spawn(TestComponent(1));
1445
entity.insert(DespawnOnAdd);
1446
assert!(entity.is_despawned());
1447
}
1448
1449
#[test]
1450
#[should_panic]
1451
fn using_despawned_entity_world_mut_panics() {
1452
let mut world = World::new();
1453
1454
let mut entity = world.spawn(TestComponent(1));
1455
entity.insert(DespawnOnAdd);
1456
assert!(entity.is_despawned());
1457
entity.insert(TestComponent2(2));
1458
}
1459
1460
#[test]
1461
fn update_despawned_by_after_observers() {
1462
let mut world = World::new();
1463
1464
#[derive(Component)]
1465
#[component(on_remove = get_tracked)]
1466
struct C;
1467
1468
static TRACKED: OnceLock<(MaybeLocation, Tick)> = OnceLock::new();
1469
fn get_tracked(world: DeferredWorld, HookContext { entity, .. }: HookContext) {
1470
TRACKED.get_or_init(|| {
1471
let by = world
1472
.entities
1473
.entity_get_spawned_or_despawned_by(entity)
1474
.map(|l| l.unwrap());
1475
let at = world
1476
.entities
1477
.entity_get_spawn_or_despawn_tick(entity)
1478
.unwrap();
1479
(by, at)
1480
});
1481
}
1482
1483
#[track_caller]
1484
fn caller_spawn(world: &mut World) -> (Entity, MaybeLocation, Tick) {
1485
let caller = MaybeLocation::caller();
1486
(world.spawn(C).id(), caller, world.change_tick())
1487
}
1488
let (entity, spawner, spawn_tick) = caller_spawn(&mut world);
1489
1490
assert_eq!(
1491
spawner,
1492
world
1493
.entities()
1494
.entity_get_spawned_or_despawned_by(entity)
1495
.map(|l| l.unwrap())
1496
);
1497
1498
#[track_caller]
1499
fn caller_despawn(world: &mut World, entity: Entity) -> (MaybeLocation, Tick) {
1500
world.despawn(entity);
1501
(MaybeLocation::caller(), world.change_tick())
1502
}
1503
let (despawner, despawn_tick) = caller_despawn(&mut world, entity);
1504
1505
assert_eq!((spawner, spawn_tick), *TRACKED.get().unwrap());
1506
assert_eq!(
1507
despawner,
1508
world
1509
.entities()
1510
.entity_get_spawned_or_despawned_by(entity)
1511
.map(|l| l.unwrap())
1512
);
1513
assert_eq!(
1514
despawn_tick,
1515
world
1516
.entities()
1517
.entity_get_spawn_or_despawn_tick(entity)
1518
.unwrap()
1519
);
1520
}
1521
1522
#[test]
1523
fn with_component_activates_hooks() {
1524
use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
1525
1526
#[derive(Component, PartialEq, Eq, Debug)]
1527
#[component(immutable)]
1528
struct Foo(bool);
1529
1530
static EXPECTED_VALUE: AtomicBool = AtomicBool::new(false);
1531
1532
static ADD_COUNT: AtomicU8 = AtomicU8::new(0);
1533
static REMOVE_COUNT: AtomicU8 = AtomicU8::new(0);
1534
static REPLACE_COUNT: AtomicU8 = AtomicU8::new(0);
1535
static INSERT_COUNT: AtomicU8 = AtomicU8::new(0);
1536
1537
let mut world = World::default();
1538
1539
world.register_component::<Foo>();
1540
world
1541
.register_component_hooks::<Foo>()
1542
.on_add(|world, context| {
1543
ADD_COUNT.fetch_add(1, Ordering::Relaxed);
1544
1545
assert_eq!(
1546
world.get(context.entity),
1547
Some(&Foo(EXPECTED_VALUE.load(Ordering::Relaxed)))
1548
);
1549
})
1550
.on_remove(|world, context| {
1551
REMOVE_COUNT.fetch_add(1, Ordering::Relaxed);
1552
1553
assert_eq!(
1554
world.get(context.entity),
1555
Some(&Foo(EXPECTED_VALUE.load(Ordering::Relaxed)))
1556
);
1557
})
1558
.on_replace(|world, context| {
1559
REPLACE_COUNT.fetch_add(1, Ordering::Relaxed);
1560
1561
assert_eq!(
1562
world.get(context.entity),
1563
Some(&Foo(EXPECTED_VALUE.load(Ordering::Relaxed)))
1564
);
1565
})
1566
.on_insert(|world, context| {
1567
INSERT_COUNT.fetch_add(1, Ordering::Relaxed);
1568
1569
assert_eq!(
1570
world.get(context.entity),
1571
Some(&Foo(EXPECTED_VALUE.load(Ordering::Relaxed)))
1572
);
1573
});
1574
1575
let entity = world.spawn(Foo(false)).id();
1576
1577
assert_eq!(ADD_COUNT.load(Ordering::Relaxed), 1);
1578
assert_eq!(REMOVE_COUNT.load(Ordering::Relaxed), 0);
1579
assert_eq!(REPLACE_COUNT.load(Ordering::Relaxed), 0);
1580
assert_eq!(INSERT_COUNT.load(Ordering::Relaxed), 1);
1581
1582
let mut entity = world.entity_mut(entity);
1583
1584
let archetype_pointer_before = &raw const *entity.archetype();
1585
1586
assert_eq!(entity.get::<Foo>(), Some(&Foo(false)));
1587
1588
entity.modify_component(|foo: &mut Foo| {
1589
foo.0 = true;
1590
EXPECTED_VALUE.store(foo.0, Ordering::Relaxed);
1591
});
1592
1593
let archetype_pointer_after = &raw const *entity.archetype();
1594
1595
assert_eq!(entity.get::<Foo>(), Some(&Foo(true)));
1596
1597
assert_eq!(ADD_COUNT.load(Ordering::Relaxed), 1);
1598
assert_eq!(REMOVE_COUNT.load(Ordering::Relaxed), 0);
1599
assert_eq!(REPLACE_COUNT.load(Ordering::Relaxed), 1);
1600
assert_eq!(INSERT_COUNT.load(Ordering::Relaxed), 2);
1601
1602
assert_eq!(archetype_pointer_before, archetype_pointer_after);
1603
}
1604
1605
#[test]
1606
fn bundle_remove_only_triggers_for_present_components() {
1607
let mut world = World::default();
1608
1609
#[derive(Component)]
1610
struct A;
1611
1612
#[derive(Component)]
1613
struct B;
1614
1615
#[derive(Resource, PartialEq, Eq, Debug)]
1616
struct Tracker {
1617
a: bool,
1618
b: bool,
1619
}
1620
1621
world.insert_resource(Tracker { a: false, b: false });
1622
let entity = world.spawn(A).id();
1623
1624
world.add_observer(|_: On<Remove, A>, mut tracker: ResMut<Tracker>| {
1625
tracker.a = true;
1626
});
1627
world.add_observer(|_: On<Remove, B>, mut tracker: ResMut<Tracker>| {
1628
tracker.b = true;
1629
});
1630
1631
world.entity_mut(entity).remove::<(A, B)>();
1632
1633
assert_eq!(
1634
world.resource::<Tracker>(),
1635
&Tracker {
1636
a: true,
1637
// The entity didn't have a B component, so it should not have been triggered.
1638
b: false,
1639
}
1640
);
1641
}
1642
1643
#[test]
1644
fn spawned_after_swap_remove() {
1645
#[derive(Component)]
1646
struct Marker;
1647
1648
let mut world = World::new();
1649
let id1 = world.spawn(Marker).id();
1650
let _id2 = world.spawn(Marker).id();
1651
let id3 = world.spawn(Marker).id();
1652
1653
let e1_spawned = world.entity(id1).spawned_by();
1654
1655
let spawn = world.entity(id3).spawned_by();
1656
world.entity_mut(id1).despawn();
1657
let e1_despawned = world.entities().entity_get_spawned_or_despawned_by(id1);
1658
1659
// These assertions are only possible if the `track_location` feature is enabled
1660
if let (Some(e1_spawned), Some(e1_despawned)) =
1661
(e1_spawned.into_option(), e1_despawned.into_option())
1662
{
1663
assert!(e1_despawned.is_some());
1664
assert_ne!(Some(e1_spawned), e1_despawned);
1665
}
1666
1667
let spawn_after = world.entity(id3).spawned_by();
1668
assert_eq!(spawn, spawn_after);
1669
}
1670
1671
#[test]
1672
fn spawned_by_set_before_flush() {
1673
#[derive(Component)]
1674
#[component(on_despawn = on_despawn)]
1675
struct C;
1676
1677
fn on_despawn(mut world: DeferredWorld, context: HookContext) {
1678
let spawned = world.entity(context.entity).spawned_by();
1679
world.commands().queue(move |world: &mut World| {
1680
// The entity has finished despawning...
1681
assert!(world.get_entity(context.entity).is_err());
1682
let despawned = world
1683
.entities()
1684
.entity_get_spawned_or_despawned_by(context.entity);
1685
// These assertions are only possible if the `track_location` feature is enabled
1686
if let (Some(spawned), Some(despawned)) =
1687
(spawned.into_option(), despawned.into_option())
1688
{
1689
// ... so ensure that `despawned_by` has been written
1690
assert!(despawned.is_some());
1691
assert_ne!(Some(spawned), despawned);
1692
}
1693
});
1694
}
1695
1696
let mut world = World::new();
1697
let original = world.spawn(C).id();
1698
world.despawn(original);
1699
}
1700
}
1701
1702