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