Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/lib.rs
6598 views
1
#![expect(
2
unsafe_op_in_unsafe_fn,
3
reason = "See #11590. To be removed once all applicable unsafe code has an unsafe block with a safety comment."
4
)]
5
#![doc = include_str!("../README.md")]
6
#![cfg_attr(
7
any(docsrs, docsrs_dep),
8
expect(
9
internal_features,
10
reason = "rustdoc_internals is needed for fake_variadic"
11
)
12
)]
13
#![cfg_attr(any(docsrs, docsrs_dep), feature(doc_auto_cfg, rustdoc_internals))]
14
#![expect(unsafe_code, reason = "Unsafe code is used to improve performance.")]
15
#![doc(
16
html_logo_url = "https://bevy.org/assets/icon.png",
17
html_favicon_url = "https://bevy.org/assets/icon.png"
18
)]
19
#![no_std]
20
21
#[cfg(feature = "std")]
22
extern crate std;
23
24
#[cfg(target_pointer_width = "16")]
25
compile_error!("bevy_ecs cannot safely compile for a 16-bit platform.");
26
27
extern crate alloc;
28
29
// Required to make proc macros work in bevy itself.
30
extern crate self as bevy_ecs;
31
32
pub mod archetype;
33
pub mod batching;
34
pub mod bundle;
35
pub mod change_detection;
36
pub mod component;
37
pub mod entity;
38
pub mod entity_disabling;
39
pub mod error;
40
pub mod event;
41
pub mod hierarchy;
42
pub mod intern;
43
pub mod label;
44
pub mod lifecycle;
45
pub mod name;
46
pub mod never;
47
pub mod observer;
48
pub mod query;
49
#[cfg(feature = "bevy_reflect")]
50
pub mod reflect;
51
pub mod relationship;
52
pub mod resource;
53
pub mod schedule;
54
pub mod spawn;
55
pub mod storage;
56
pub mod system;
57
pub mod traversal;
58
pub mod world;
59
60
pub use bevy_ptr as ptr;
61
62
#[cfg(feature = "hotpatching")]
63
use event::BufferedEvent;
64
65
/// The ECS prelude.
66
///
67
/// This includes the most common types in this crate, re-exported for your convenience.
68
pub mod prelude {
69
#[doc(hidden)]
70
#[expect(
71
deprecated,
72
reason = "`Trigger` was deprecated in favor of `On`, and `OnX` lifecycle events were deprecated in favor of `X` events."
73
)]
74
pub use crate::{
75
bundle::Bundle,
76
change_detection::{DetectChanges, DetectChangesMut, Mut, Ref},
77
children,
78
component::Component,
79
entity::{ContainsEntity, Entity, EntityMapper},
80
error::{BevyError, Result},
81
event::{
82
BufferedEvent, EntityEvent, Event, EventKey, EventMutator, EventReader, EventWriter,
83
Events,
84
},
85
hierarchy::{ChildOf, ChildSpawner, ChildSpawnerCommands, Children},
86
lifecycle::{
87
Add, Despawn, Insert, OnAdd, OnDespawn, OnInsert, OnRemove, OnReplace, Remove,
88
RemovedComponents, Replace,
89
},
90
name::{Name, NameOrEntity},
91
observer::{Observer, On, Trigger},
92
query::{Added, Allow, AnyOf, Changed, Has, Or, QueryBuilder, QueryState, With, Without},
93
related,
94
relationship::RelationshipTarget,
95
resource::Resource,
96
schedule::{
97
common_conditions::*, ApplyDeferred, IntoScheduleConfigs, IntoSystemSet, Schedule,
98
Schedules, SystemCondition, SystemSet,
99
},
100
spawn::{Spawn, SpawnIter, SpawnRelated, SpawnWith, WithOneRelated, WithRelated},
101
system::{
102
Command, Commands, Deferred, EntityCommand, EntityCommands, If, In, InMut, InRef,
103
IntoSystem, Local, NonSend, NonSendMut, ParamSet, Populated, Query, ReadOnlySystem,
104
Res, ResMut, Single, System, SystemIn, SystemInput, SystemParamBuilder,
105
SystemParamFunction,
106
},
107
world::{
108
EntityMut, EntityRef, EntityWorldMut, FilteredResources, FilteredResourcesMut,
109
FromWorld, World,
110
},
111
};
112
113
#[doc(hidden)]
114
#[cfg(feature = "std")]
115
pub use crate::system::ParallelCommands;
116
117
#[doc(hidden)]
118
#[cfg(feature = "bevy_reflect")]
119
pub use crate::reflect::{
120
AppTypeRegistry, ReflectComponent, ReflectFromWorld, ReflectResource,
121
};
122
123
#[doc(hidden)]
124
#[cfg(feature = "reflect_functions")]
125
pub use crate::reflect::AppFunctionRegistry;
126
}
127
128
/// Exports used by macros.
129
///
130
/// These are not meant to be used directly and are subject to breaking changes.
131
#[doc(hidden)]
132
pub mod __macro_exports {
133
// Cannot directly use `alloc::vec::Vec` in macros, as a crate may not have
134
// included `extern crate alloc;`. This re-export ensures we have access
135
// to `Vec` in `no_std` and `std` contexts.
136
pub use alloc::vec::Vec;
137
}
138
139
/// Event sent when a hotpatch happens.
140
///
141
/// Can be used for causing custom behavior on hot-patch.
142
#[cfg(feature = "hotpatching")]
143
#[derive(BufferedEvent, Default)]
144
pub struct HotPatched;
145
146
/// Resource which "changes" when a hotpatch happens.
147
///
148
/// Exists solely for change-detection, which allows systems to
149
/// know whether a hotpatch happened even if they only run irregularily and would
150
/// miss the event.
151
///
152
/// Used by Executors and other places which run systems
153
/// [`System::refresh_hotpatch`](crate::system::System::refresh_hotpatch) only when necessary.
154
#[cfg(feature = "hotpatching")]
155
#[derive(resource::Resource, Default)]
156
pub struct HotPatchChanges;
157
158
#[cfg(test)]
159
mod tests {
160
use crate::{
161
bundle::Bundle,
162
change_detection::Ref,
163
component::Component,
164
entity::{Entity, EntityMapper},
165
entity_disabling::DefaultQueryFilters,
166
prelude::Or,
167
query::{Added, Changed, FilteredAccess, QueryFilter, With, Without},
168
resource::Resource,
169
world::{EntityMut, EntityRef, Mut, World},
170
};
171
use alloc::{string::String, sync::Arc, vec, vec::Vec};
172
use bevy_platform::collections::HashSet;
173
use bevy_tasks::{ComputeTaskPool, TaskPool};
174
use core::{
175
any::TypeId,
176
marker::PhantomData,
177
sync::atomic::{AtomicUsize, Ordering},
178
};
179
use std::sync::Mutex;
180
181
#[derive(Component, Resource, Debug, PartialEq, Eq, Hash, Clone, Copy)]
182
struct A(usize);
183
#[derive(Component, Debug, PartialEq, Eq, Hash, Clone, Copy)]
184
struct B(usize);
185
#[derive(Component, Debug, PartialEq, Eq, Clone, Copy)]
186
struct C;
187
188
#[derive(Default)]
189
struct NonSendA(PhantomData<*mut ()>);
190
191
#[derive(Component, Clone, Debug)]
192
struct DropCk(Arc<AtomicUsize>);
193
impl DropCk {
194
fn new_pair() -> (Self, Arc<AtomicUsize>) {
195
let atomic = Arc::new(AtomicUsize::new(0));
196
(DropCk(atomic.clone()), atomic)
197
}
198
}
199
200
impl Drop for DropCk {
201
fn drop(&mut self) {
202
self.0.as_ref().fetch_add(1, Ordering::Relaxed);
203
}
204
}
205
206
#[expect(
207
dead_code,
208
reason = "This struct is used to test how `Drop` behavior works in regards to SparseSet storage, and as such is solely a wrapper around `DropCk` to make it use the SparseSet storage. Because of this, the inner field is intentionally never read."
209
)]
210
#[derive(Component, Clone, Debug)]
211
#[component(storage = "SparseSet")]
212
struct DropCkSparse(DropCk);
213
214
#[derive(Component, Copy, Clone, PartialEq, Eq, Debug)]
215
#[component(storage = "Table")]
216
struct TableStored(&'static str);
217
#[derive(Component, Copy, Clone, PartialEq, Eq, Hash, Debug)]
218
#[component(storage = "SparseSet")]
219
struct SparseStored(u32);
220
221
#[test]
222
fn random_access() {
223
let mut world = World::new();
224
225
let e = world.spawn((TableStored("abc"), SparseStored(123))).id();
226
let f = world
227
.spawn((TableStored("def"), SparseStored(456), A(1)))
228
.id();
229
assert_eq!(world.get::<TableStored>(e).unwrap().0, "abc");
230
assert_eq!(world.get::<SparseStored>(e).unwrap().0, 123);
231
assert_eq!(world.get::<TableStored>(f).unwrap().0, "def");
232
assert_eq!(world.get::<SparseStored>(f).unwrap().0, 456);
233
234
// test archetype get_mut()
235
world.get_mut::<TableStored>(e).unwrap().0 = "xyz";
236
assert_eq!(world.get::<TableStored>(e).unwrap().0, "xyz");
237
238
// test sparse set get_mut()
239
world.get_mut::<SparseStored>(f).unwrap().0 = 42;
240
assert_eq!(world.get::<SparseStored>(f).unwrap().0, 42);
241
}
242
243
#[test]
244
fn bundle_derive() {
245
let mut world = World::new();
246
247
#[derive(Bundle, PartialEq, Debug)]
248
struct FooBundle {
249
x: TableStored,
250
y: SparseStored,
251
}
252
let mut ids = Vec::new();
253
<FooBundle as Bundle>::component_ids(&mut world.components_registrator(), &mut |id| {
254
ids.push(id);
255
});
256
257
assert_eq!(
258
ids,
259
&[
260
world.register_component::<TableStored>(),
261
world.register_component::<SparseStored>(),
262
]
263
);
264
265
let e1 = world
266
.spawn(FooBundle {
267
x: TableStored("abc"),
268
y: SparseStored(123),
269
})
270
.id();
271
let e2 = world
272
.spawn((TableStored("def"), SparseStored(456), A(1)))
273
.id();
274
assert_eq!(world.get::<TableStored>(e1).unwrap().0, "abc");
275
assert_eq!(world.get::<SparseStored>(e1).unwrap().0, 123);
276
assert_eq!(world.get::<TableStored>(e2).unwrap().0, "def");
277
assert_eq!(world.get::<SparseStored>(e2).unwrap().0, 456);
278
279
// test archetype get_mut()
280
world.get_mut::<TableStored>(e1).unwrap().0 = "xyz";
281
assert_eq!(world.get::<TableStored>(e1).unwrap().0, "xyz");
282
283
// test sparse set get_mut()
284
world.get_mut::<SparseStored>(e2).unwrap().0 = 42;
285
assert_eq!(world.get::<SparseStored>(e2).unwrap().0, 42);
286
287
assert_eq!(
288
world.entity_mut(e1).take::<FooBundle>().unwrap(),
289
FooBundle {
290
x: TableStored("xyz"),
291
y: SparseStored(123),
292
}
293
);
294
295
#[derive(Bundle, PartialEq, Debug)]
296
struct NestedBundle {
297
a: A,
298
foo: FooBundle,
299
b: B,
300
}
301
302
let mut ids = Vec::new();
303
<NestedBundle as Bundle>::component_ids(&mut world.components_registrator(), &mut |id| {
304
ids.push(id);
305
});
306
307
assert_eq!(
308
ids,
309
&[
310
world.register_component::<A>(),
311
world.register_component::<TableStored>(),
312
world.register_component::<SparseStored>(),
313
world.register_component::<B>(),
314
]
315
);
316
317
let e3 = world
318
.spawn(NestedBundle {
319
a: A(1),
320
foo: FooBundle {
321
x: TableStored("ghi"),
322
y: SparseStored(789),
323
},
324
b: B(2),
325
})
326
.id();
327
328
assert_eq!(world.get::<TableStored>(e3).unwrap().0, "ghi");
329
assert_eq!(world.get::<SparseStored>(e3).unwrap().0, 789);
330
assert_eq!(world.get::<A>(e3).unwrap().0, 1);
331
assert_eq!(world.get::<B>(e3).unwrap().0, 2);
332
assert_eq!(
333
world.entity_mut(e3).take::<NestedBundle>().unwrap(),
334
NestedBundle {
335
a: A(1),
336
foo: FooBundle {
337
x: TableStored("ghi"),
338
y: SparseStored(789),
339
},
340
b: B(2),
341
}
342
);
343
344
#[derive(Default, Component, PartialEq, Debug)]
345
struct Ignored;
346
347
#[derive(Bundle, PartialEq, Debug)]
348
struct BundleWithIgnored {
349
c: C,
350
#[bundle(ignore)]
351
ignored: Ignored,
352
}
353
354
let mut ids = Vec::new();
355
<BundleWithIgnored as Bundle>::component_ids(
356
&mut world.components_registrator(),
357
&mut |id| {
358
ids.push(id);
359
},
360
);
361
362
assert_eq!(ids, &[world.register_component::<C>(),]);
363
364
let e4 = world
365
.spawn(BundleWithIgnored {
366
c: C,
367
ignored: Ignored,
368
})
369
.id();
370
371
assert_eq!(world.get::<C>(e4).unwrap(), &C);
372
assert_eq!(world.get::<Ignored>(e4), None);
373
374
assert_eq!(
375
world.entity_mut(e4).take::<BundleWithIgnored>().unwrap(),
376
BundleWithIgnored {
377
c: C,
378
ignored: Ignored,
379
}
380
);
381
}
382
383
#[test]
384
fn despawn_table_storage() {
385
let mut world = World::new();
386
let e = world.spawn((TableStored("abc"), A(123))).id();
387
let f = world.spawn((TableStored("def"), A(456))).id();
388
assert_eq!(world.query::<&TableStored>().query(&world).count(), 2);
389
assert!(world.despawn(e));
390
assert_eq!(world.query::<&TableStored>().query(&world).count(), 1);
391
assert!(world.get::<TableStored>(e).is_none());
392
assert!(world.get::<A>(e).is_none());
393
assert_eq!(world.get::<TableStored>(f).unwrap().0, "def");
394
assert_eq!(world.get::<A>(f).unwrap().0, 456);
395
}
396
397
#[test]
398
fn despawn_mixed_storage() {
399
let mut world = World::new();
400
401
let e = world.spawn((TableStored("abc"), SparseStored(123))).id();
402
let f = world.spawn((TableStored("def"), SparseStored(456))).id();
403
assert_eq!(world.query::<&TableStored>().query(&world).count(), 2);
404
assert!(world.despawn(e));
405
assert_eq!(world.query::<&TableStored>().query(&world).count(), 1);
406
assert!(world.get::<TableStored>(e).is_none());
407
assert!(world.get::<SparseStored>(e).is_none());
408
assert_eq!(world.get::<TableStored>(f).unwrap().0, "def");
409
assert_eq!(world.get::<SparseStored>(f).unwrap().0, 456);
410
}
411
412
#[test]
413
fn query_all() {
414
let mut world = World::new();
415
let e = world.spawn((TableStored("abc"), A(123))).id();
416
let f = world.spawn((TableStored("def"), A(456))).id();
417
418
let ents = world
419
.query::<(Entity, &A, &TableStored)>()
420
.iter(&world)
421
.map(|(e, &i, &s)| (e, i, s))
422
.collect::<Vec<_>>();
423
assert_eq!(
424
ents,
425
&[
426
(e, A(123), TableStored("abc")),
427
(f, A(456), TableStored("def"))
428
]
429
);
430
}
431
432
#[test]
433
fn query_all_for_each() {
434
let mut world = World::new();
435
let e = world.spawn((TableStored("abc"), A(123))).id();
436
let f = world.spawn((TableStored("def"), A(456))).id();
437
438
let mut results = Vec::new();
439
world
440
.query::<(Entity, &A, &TableStored)>()
441
.iter(&world)
442
.for_each(|(e, &i, &s)| results.push((e, i, s)));
443
assert_eq!(
444
results,
445
&[
446
(e, A(123), TableStored("abc")),
447
(f, A(456), TableStored("def"))
448
]
449
);
450
}
451
452
#[test]
453
fn query_single_component() {
454
let mut world = World::new();
455
let e = world.spawn((TableStored("abc"), A(123))).id();
456
let f = world.spawn((TableStored("def"), A(456), B(1))).id();
457
let ents = world
458
.query::<(Entity, &A)>()
459
.iter(&world)
460
.map(|(e, &i)| (e, i))
461
.collect::<HashSet<_>>();
462
assert!(ents.contains(&(e, A(123))));
463
assert!(ents.contains(&(f, A(456))));
464
}
465
466
#[test]
467
fn stateful_query_handles_new_archetype() {
468
let mut world = World::new();
469
let e = world.spawn((TableStored("abc"), A(123))).id();
470
let mut query = world.query::<(Entity, &A)>();
471
472
let ents = query.iter(&world).map(|(e, &i)| (e, i)).collect::<Vec<_>>();
473
assert_eq!(ents, &[(e, A(123))]);
474
475
let f = world.spawn((TableStored("def"), A(456), B(1))).id();
476
let ents = query.iter(&world).map(|(e, &i)| (e, i)).collect::<Vec<_>>();
477
assert_eq!(ents, &[(e, A(123)), (f, A(456))]);
478
}
479
480
#[test]
481
fn query_single_component_for_each() {
482
let mut world = World::new();
483
let e = world.spawn((TableStored("abc"), A(123))).id();
484
let f = world.spawn((TableStored("def"), A(456), B(1))).id();
485
let mut results = <HashSet<_>>::default();
486
world
487
.query::<(Entity, &A)>()
488
.iter(&world)
489
.for_each(|(e, &i)| {
490
results.insert((e, i));
491
});
492
assert!(results.contains(&(e, A(123))));
493
assert!(results.contains(&(f, A(456))));
494
}
495
496
#[test]
497
fn par_for_each_dense() {
498
ComputeTaskPool::get_or_init(TaskPool::default);
499
let mut world = World::new();
500
let e1 = world.spawn(A(1)).id();
501
let e2 = world.spawn(A(2)).id();
502
let e3 = world.spawn(A(3)).id();
503
let e4 = world.spawn((A(4), B(1))).id();
504
let e5 = world.spawn((A(5), B(1))).id();
505
let results = Arc::new(Mutex::new(Vec::new()));
506
world
507
.query::<(Entity, &A)>()
508
.par_iter(&world)
509
.for_each(|(e, &A(i))| {
510
results.lock().unwrap().push((e, i));
511
});
512
results.lock().unwrap().sort();
513
let mut expected = [(e1, 1), (e2, 2), (e3, 3), (e4, 4), (e5, 5)];
514
expected.sort();
515
assert_eq!(&*results.lock().unwrap(), &expected);
516
}
517
518
#[test]
519
fn par_for_each_sparse() {
520
ComputeTaskPool::get_or_init(TaskPool::default);
521
let mut world = World::new();
522
let e1 = world.spawn(SparseStored(1)).id();
523
let e2 = world.spawn(SparseStored(2)).id();
524
let e3 = world.spawn(SparseStored(3)).id();
525
let e4 = world.spawn((SparseStored(4), A(1))).id();
526
let e5 = world.spawn((SparseStored(5), A(1))).id();
527
let results = Arc::new(Mutex::new(Vec::new()));
528
world
529
.query::<(Entity, &SparseStored)>()
530
.par_iter(&world)
531
.for_each(|(e, &SparseStored(i))| results.lock().unwrap().push((e, i)));
532
results.lock().unwrap().sort();
533
let mut expected = [(e1, 1), (e2, 2), (e3, 3), (e4, 4), (e5, 5)];
534
expected.sort();
535
assert_eq!(&*results.lock().unwrap(), &expected);
536
}
537
538
#[test]
539
fn query_missing_component() {
540
let mut world = World::new();
541
world.spawn((TableStored("abc"), A(123)));
542
world.spawn((TableStored("def"), A(456)));
543
assert!(world.query::<(&B, &A)>().iter(&world).next().is_none());
544
}
545
546
#[test]
547
fn query_sparse_component() {
548
let mut world = World::new();
549
world.spawn((TableStored("abc"), A(123)));
550
let f = world.spawn((TableStored("def"), A(456), B(1))).id();
551
let ents = world
552
.query::<(Entity, &B)>()
553
.iter(&world)
554
.map(|(e, &b)| (e, b))
555
.collect::<Vec<_>>();
556
assert_eq!(ents, &[(f, B(1))]);
557
}
558
559
#[test]
560
fn query_filter_with() {
561
let mut world = World::new();
562
world.spawn((A(123), B(1)));
563
world.spawn(A(456));
564
let result = world
565
.query_filtered::<&A, With<B>>()
566
.iter(&world)
567
.cloned()
568
.collect::<Vec<_>>();
569
assert_eq!(result, vec![A(123)]);
570
}
571
572
#[test]
573
fn query_filter_with_for_each() {
574
let mut world = World::new();
575
world.spawn((A(123), B(1)));
576
world.spawn(A(456));
577
578
let mut results = Vec::new();
579
world
580
.query_filtered::<&A, With<B>>()
581
.iter(&world)
582
.for_each(|i| results.push(*i));
583
assert_eq!(results, vec![A(123)]);
584
}
585
586
#[test]
587
fn query_filter_with_sparse() {
588
let mut world = World::new();
589
590
world.spawn((A(123), SparseStored(321)));
591
world.spawn(A(456));
592
let result = world
593
.query_filtered::<&A, With<SparseStored>>()
594
.iter(&world)
595
.cloned()
596
.collect::<Vec<_>>();
597
assert_eq!(result, vec![A(123)]);
598
}
599
600
#[test]
601
fn query_filter_with_sparse_for_each() {
602
let mut world = World::new();
603
604
world.spawn((A(123), SparseStored(321)));
605
world.spawn(A(456));
606
let mut results = Vec::new();
607
world
608
.query_filtered::<&A, With<SparseStored>>()
609
.iter(&world)
610
.for_each(|i| results.push(*i));
611
assert_eq!(results, vec![A(123)]);
612
}
613
614
#[test]
615
fn query_filter_without() {
616
let mut world = World::new();
617
world.spawn((A(123), B(321)));
618
world.spawn(A(456));
619
let result = world
620
.query_filtered::<&A, Without<B>>()
621
.iter(&world)
622
.cloned()
623
.collect::<Vec<_>>();
624
assert_eq!(result, vec![A(456)]);
625
}
626
627
#[test]
628
fn query_optional_component_table() {
629
let mut world = World::new();
630
let e = world.spawn((TableStored("abc"), A(123))).id();
631
let f = world.spawn((TableStored("def"), A(456), B(1))).id();
632
// this should be skipped
633
world.spawn(TableStored("abc"));
634
let ents = world
635
.query::<(Entity, Option<&B>, &A)>()
636
.iter(&world)
637
.map(|(e, b, &i)| (e, b.copied(), i))
638
.collect::<HashSet<_>>();
639
assert!(ents.contains(&(e, None, A(123))));
640
assert!(ents.contains(&(f, Some(B(1)), A(456))));
641
}
642
643
#[test]
644
fn query_optional_component_sparse() {
645
let mut world = World::new();
646
647
let e = world.spawn((TableStored("abc"), A(123))).id();
648
let f = world
649
.spawn((TableStored("def"), A(456), SparseStored(1)))
650
.id();
651
// this should be skipped
652
// world.spawn(SparseStored(1));
653
let ents = world
654
.query::<(Entity, Option<&SparseStored>, &A)>()
655
.iter(&world)
656
.map(|(e, b, &i)| (e, b.copied(), i))
657
.collect::<HashSet<_>>();
658
assert_eq!(
659
ents,
660
[(e, None, A(123)), (f, Some(SparseStored(1)), A(456))]
661
.into_iter()
662
.collect::<HashSet<_>>()
663
);
664
}
665
666
#[test]
667
fn query_optional_component_sparse_no_match() {
668
let mut world = World::new();
669
670
let e = world.spawn((TableStored("abc"), A(123))).id();
671
let f = world.spawn((TableStored("def"), A(456))).id();
672
// // this should be skipped
673
world.spawn(TableStored("abc"));
674
let ents = world
675
.query::<(Entity, Option<&SparseStored>, &A)>()
676
.iter(&world)
677
.map(|(e, b, &i)| (e, b.copied(), i))
678
.collect::<Vec<_>>();
679
assert_eq!(ents, &[(e, None, A(123)), (f, None, A(456))]);
680
}
681
682
#[test]
683
fn add_remove_components() {
684
let mut world = World::new();
685
let e1 = world.spawn((A(1), B(3), TableStored("abc"))).id();
686
let e2 = world.spawn((A(2), B(4), TableStored("xyz"))).id();
687
688
assert_eq!(
689
world
690
.query::<(Entity, &A, &B)>()
691
.iter(&world)
692
.map(|(e, &i, &b)| (e, i, b))
693
.collect::<HashSet<_>>(),
694
[(e1, A(1), B(3)), (e2, A(2), B(4))]
695
.into_iter()
696
.collect::<HashSet<_>>()
697
);
698
assert_eq!(world.entity_mut(e1).take::<A>(), Some(A(1)));
699
assert_eq!(
700
world
701
.query::<(Entity, &A, &B)>()
702
.iter(&world)
703
.map(|(e, &i, &b)| (e, i, b))
704
.collect::<Vec<_>>(),
705
&[(e2, A(2), B(4))]
706
);
707
assert_eq!(
708
world
709
.query::<(Entity, &B, &TableStored)>()
710
.iter(&world)
711
.map(|(e, &B(b), &TableStored(s))| (e, b, s))
712
.collect::<HashSet<_>>(),
713
[(e2, 4, "xyz"), (e1, 3, "abc")]
714
.into_iter()
715
.collect::<HashSet<_>>()
716
);
717
world.entity_mut(e1).insert(A(43));
718
assert_eq!(
719
world
720
.query::<(Entity, &A, &B)>()
721
.iter(&world)
722
.map(|(e, &i, &b)| (e, i, b))
723
.collect::<HashSet<_>>(),
724
[(e2, A(2), B(4)), (e1, A(43), B(3))]
725
.into_iter()
726
.collect::<HashSet<_>>()
727
);
728
world.entity_mut(e1).insert(C);
729
assert_eq!(
730
world
731
.query::<(Entity, &C)>()
732
.iter(&world)
733
.map(|(e, &f)| (e, f))
734
.collect::<Vec<_>>(),
735
&[(e1, C)]
736
);
737
}
738
739
#[test]
740
fn table_add_remove_many() {
741
let mut world = World::default();
742
#[cfg(miri)]
743
let (mut entities, to) = {
744
let to = 10;
745
(Vec::with_capacity(to), to)
746
};
747
#[cfg(not(miri))]
748
let (mut entities, to) = {
749
let to = 10_000;
750
(Vec::with_capacity(to), to)
751
};
752
753
for _ in 0..to {
754
entities.push(world.spawn(B(0)).id());
755
}
756
757
for (i, entity) in entities.iter().cloned().enumerate() {
758
world.entity_mut(entity).insert(A(i));
759
}
760
761
for (i, entity) in entities.iter().cloned().enumerate() {
762
assert_eq!(world.entity_mut(entity).take::<A>(), Some(A(i)));
763
}
764
}
765
766
#[test]
767
fn sparse_set_add_remove_many() {
768
let mut world = World::default();
769
770
let mut entities = Vec::with_capacity(1000);
771
for _ in 0..4 {
772
entities.push(world.spawn(A(2)).id());
773
}
774
775
for (i, entity) in entities.iter().cloned().enumerate() {
776
world.entity_mut(entity).insert(SparseStored(i as u32));
777
}
778
779
for (i, entity) in entities.iter().cloned().enumerate() {
780
assert_eq!(
781
world.entity_mut(entity).take::<SparseStored>(),
782
Some(SparseStored(i as u32))
783
);
784
}
785
}
786
787
#[test]
788
fn remove_missing() {
789
let mut world = World::new();
790
let e = world.spawn((TableStored("abc"), A(123))).id();
791
assert!(world.entity_mut(e).take::<B>().is_none());
792
}
793
794
#[test]
795
fn spawn_batch() {
796
let mut world = World::new();
797
world.spawn_batch((0..100).map(|x| (A(x), TableStored("abc"))));
798
let values = world
799
.query::<&A>()
800
.iter(&world)
801
.map(|v| v.0)
802
.collect::<Vec<_>>();
803
let expected = (0..100).collect::<Vec<_>>();
804
assert_eq!(values, expected);
805
}
806
807
#[test]
808
fn query_get() {
809
let mut world = World::new();
810
let a = world.spawn((TableStored("abc"), A(123))).id();
811
let b = world.spawn((TableStored("def"), A(456))).id();
812
let c = world.spawn((TableStored("ghi"), A(789), B(1))).id();
813
814
let mut i32_query = world.query::<&A>();
815
assert_eq!(i32_query.get(&world, a).unwrap().0, 123);
816
assert_eq!(i32_query.get(&world, b).unwrap().0, 456);
817
818
let mut i32_bool_query = world.query::<(&A, &B)>();
819
assert!(i32_bool_query.get(&world, a).is_err());
820
assert_eq!(i32_bool_query.get(&world, c).unwrap(), (&A(789), &B(1)));
821
assert!(world.despawn(a));
822
assert!(i32_query.get(&world, a).is_err());
823
}
824
825
#[test]
826
fn query_get_works_across_sparse_removal() {
827
// Regression test for: https://github.com/bevyengine/bevy/issues/6623
828
let mut world = World::new();
829
let a = world.spawn((TableStored("abc"), SparseStored(123))).id();
830
let b = world.spawn((TableStored("def"), SparseStored(456))).id();
831
let c = world
832
.spawn((TableStored("ghi"), SparseStored(789), B(1)))
833
.id();
834
835
let mut query = world.query::<&TableStored>();
836
assert_eq!(query.get(&world, a).unwrap(), &TableStored("abc"));
837
assert_eq!(query.get(&world, b).unwrap(), &TableStored("def"));
838
assert_eq!(query.get(&world, c).unwrap(), &TableStored("ghi"));
839
840
world.entity_mut(b).remove::<SparseStored>();
841
world.entity_mut(c).remove::<SparseStored>();
842
843
assert_eq!(query.get(&world, a).unwrap(), &TableStored("abc"));
844
assert_eq!(query.get(&world, b).unwrap(), &TableStored("def"));
845
assert_eq!(query.get(&world, c).unwrap(), &TableStored("ghi"));
846
}
847
848
#[test]
849
fn remove_tracking() {
850
let mut world = World::new();
851
852
let a = world.spawn((SparseStored(0), A(123))).id();
853
let b = world.spawn((SparseStored(1), A(123))).id();
854
855
world.entity_mut(a).despawn();
856
assert_eq!(
857
world.removed::<A>().collect::<Vec<_>>(),
858
&[a],
859
"despawning results in 'removed component' state for table components"
860
);
861
assert_eq!(
862
world.removed::<SparseStored>().collect::<Vec<_>>(),
863
&[a],
864
"despawning results in 'removed component' state for sparse set components"
865
);
866
867
world.entity_mut(b).insert(B(1));
868
assert_eq!(
869
world.removed::<A>().collect::<Vec<_>>(),
870
&[a],
871
"archetype moves does not result in 'removed component' state"
872
);
873
874
world.entity_mut(b).remove::<A>();
875
assert_eq!(
876
world.removed::<A>().collect::<Vec<_>>(),
877
&[a, b],
878
"removing a component results in a 'removed component' state"
879
);
880
881
world.clear_trackers();
882
assert_eq!(
883
world.removed::<A>().collect::<Vec<_>>(),
884
&[],
885
"clearing trackers clears removals"
886
);
887
assert_eq!(
888
world.removed::<SparseStored>().collect::<Vec<_>>(),
889
&[],
890
"clearing trackers clears removals"
891
);
892
assert_eq!(
893
world.removed::<B>().collect::<Vec<_>>(),
894
&[],
895
"clearing trackers clears removals"
896
);
897
898
// TODO: uncomment when world.clear() is implemented
899
// let c = world.spawn(("abc", 123)).id();
900
// let d = world.spawn(("abc", 123)).id();
901
// world.clear();
902
// assert_eq!(
903
// world.removed::<i32>(),
904
// &[c, d],
905
// "world clears result in 'removed component' states"
906
// );
907
// assert_eq!(
908
// world.removed::<&'static str>(),
909
// &[c, d, b],
910
// "world clears result in 'removed component' states"
911
// );
912
// assert_eq!(
913
// world.removed::<f64>(),
914
// &[b],
915
// "world clears result in 'removed component' states"
916
// );
917
}
918
919
#[test]
920
fn added_tracking() {
921
let mut world = World::new();
922
let a = world.spawn(A(123)).id();
923
924
assert_eq!(world.query::<&A>().iter(&world).count(), 1);
925
assert_eq!(
926
world.query_filtered::<(), Added<A>>().iter(&world).count(),
927
1
928
);
929
assert_eq!(world.query::<&A>().iter(&world).count(), 1);
930
assert_eq!(
931
world.query_filtered::<(), Added<A>>().iter(&world).count(),
932
1
933
);
934
assert!(world.query::<&A>().get(&world, a).is_ok());
935
assert!(world
936
.query_filtered::<(), Added<A>>()
937
.get(&world, a)
938
.is_ok());
939
assert!(world.query::<&A>().get(&world, a).is_ok());
940
assert!(world
941
.query_filtered::<(), Added<A>>()
942
.get(&world, a)
943
.is_ok());
944
945
world.clear_trackers();
946
947
assert_eq!(world.query::<&A>().iter(&world).count(), 1);
948
assert_eq!(
949
world.query_filtered::<(), Added<A>>().iter(&world).count(),
950
0
951
);
952
assert_eq!(world.query::<&A>().iter(&world).count(), 1);
953
assert_eq!(
954
world.query_filtered::<(), Added<A>>().iter(&world).count(),
955
0
956
);
957
assert!(world.query::<&A>().get(&world, a).is_ok());
958
assert!(world
959
.query_filtered::<(), Added<A>>()
960
.get(&world, a)
961
.is_err());
962
assert!(world.query::<&A>().get(&world, a).is_ok());
963
assert!(world
964
.query_filtered::<(), Added<A>>()
965
.get(&world, a)
966
.is_err());
967
}
968
969
#[test]
970
fn added_queries() {
971
let mut world = World::default();
972
let e1 = world.spawn(A(0)).id();
973
974
fn get_added<Com: Component>(world: &mut World) -> Vec<Entity> {
975
world
976
.query_filtered::<Entity, Added<Com>>()
977
.iter(world)
978
.collect::<Vec<Entity>>()
979
}
980
981
assert_eq!(get_added::<A>(&mut world), vec![e1]);
982
world.entity_mut(e1).insert(B(0));
983
assert_eq!(get_added::<A>(&mut world), vec![e1]);
984
assert_eq!(get_added::<B>(&mut world), vec![e1]);
985
986
world.clear_trackers();
987
assert!(get_added::<A>(&mut world).is_empty());
988
let e2 = world.spawn((A(1), B(1))).id();
989
assert_eq!(get_added::<A>(&mut world), vec![e2]);
990
assert_eq!(get_added::<B>(&mut world), vec![e2]);
991
992
let added = world
993
.query_filtered::<Entity, (Added<A>, Added<B>)>()
994
.iter(&world)
995
.collect::<Vec<Entity>>();
996
assert_eq!(added, vec![e2]);
997
}
998
999
#[test]
1000
fn changed_trackers() {
1001
let mut world = World::default();
1002
let e1 = world.spawn((A(0), B(0))).id();
1003
let e2 = world.spawn((A(0), B(0))).id();
1004
let e3 = world.spawn((A(0), B(0))).id();
1005
world.spawn((A(0), B(0)));
1006
1007
world.clear_trackers();
1008
1009
for (i, mut a) in world.query::<&mut A>().iter_mut(&mut world).enumerate() {
1010
if i % 2 == 0 {
1011
a.0 += 1;
1012
}
1013
}
1014
1015
fn get_filtered<F: QueryFilter>(world: &mut World) -> HashSet<Entity> {
1016
world
1017
.query_filtered::<Entity, F>()
1018
.iter(world)
1019
.collect::<HashSet<Entity>>()
1020
}
1021
1022
assert_eq!(
1023
get_filtered::<Changed<A>>(&mut world),
1024
[e1, e3].into_iter().collect::<HashSet<_>>()
1025
);
1026
1027
// ensure changing an entity's archetypes also moves its changed state
1028
world.entity_mut(e1).insert(C);
1029
1030
assert_eq!(
1031
get_filtered::<Changed<A>>(&mut world),
1032
[e3, e1].into_iter().collect::<HashSet<_>>(),
1033
"changed entities list should not change"
1034
);
1035
1036
// spawning a new A entity should not change existing changed state
1037
world.entity_mut(e1).insert((A(0), B(0)));
1038
1039
assert_eq!(
1040
get_filtered::<Changed<A>>(&mut world),
1041
[e3, e1].into_iter().collect::<HashSet<_>>(),
1042
"changed entities list should not change"
1043
);
1044
1045
// removing an unchanged entity should not change changed state
1046
assert!(world.despawn(e2));
1047
assert_eq!(
1048
get_filtered::<Changed<A>>(&mut world),
1049
[e3, e1].into_iter().collect::<HashSet<_>>(),
1050
"changed entities list should not change"
1051
);
1052
1053
// removing a changed entity should remove it from enumeration
1054
assert!(world.despawn(e1));
1055
assert_eq!(
1056
get_filtered::<Changed<A>>(&mut world),
1057
[e3].into_iter().collect::<HashSet<_>>(),
1058
"e1 should no longer be returned"
1059
);
1060
1061
world.clear_trackers();
1062
1063
assert!(get_filtered::<Changed<A>>(&mut world).is_empty());
1064
1065
let e4 = world.spawn_empty().id();
1066
1067
world.entity_mut(e4).insert(A(0));
1068
assert_eq!(
1069
get_filtered::<Changed<A>>(&mut world),
1070
[e4].into_iter().collect::<HashSet<_>>()
1071
);
1072
assert_eq!(
1073
get_filtered::<Added<A>>(&mut world),
1074
[e4].into_iter().collect::<HashSet<_>>()
1075
);
1076
1077
world.entity_mut(e4).insert(A(1));
1078
assert_eq!(
1079
get_filtered::<Changed<A>>(&mut world),
1080
[e4].into_iter().collect::<HashSet<_>>()
1081
);
1082
1083
world.clear_trackers();
1084
1085
// ensure inserting multiple components set changed state for all components and set added
1086
// state for non existing components even when changing archetype.
1087
world.entity_mut(e4).insert((A(0), B(0)));
1088
1089
assert!(get_filtered::<Added<A>>(&mut world).is_empty());
1090
assert_eq!(
1091
get_filtered::<Changed<A>>(&mut world),
1092
[e4].into_iter().collect::<HashSet<_>>()
1093
);
1094
assert_eq!(
1095
get_filtered::<Added<B>>(&mut world),
1096
[e4].into_iter().collect::<HashSet<_>>()
1097
);
1098
assert_eq!(
1099
get_filtered::<Changed<B>>(&mut world),
1100
[e4].into_iter().collect::<HashSet<_>>()
1101
);
1102
}
1103
1104
#[test]
1105
fn changed_trackers_sparse() {
1106
let mut world = World::default();
1107
let e1 = world.spawn(SparseStored(0)).id();
1108
let e2 = world.spawn(SparseStored(0)).id();
1109
let e3 = world.spawn(SparseStored(0)).id();
1110
world.spawn(SparseStored(0));
1111
1112
world.clear_trackers();
1113
1114
for (i, mut a) in world
1115
.query::<&mut SparseStored>()
1116
.iter_mut(&mut world)
1117
.enumerate()
1118
{
1119
if i % 2 == 0 {
1120
a.0 += 1;
1121
}
1122
}
1123
1124
fn get_filtered<F: QueryFilter>(world: &mut World) -> HashSet<Entity> {
1125
world
1126
.query_filtered::<Entity, F>()
1127
.iter(world)
1128
.collect::<HashSet<Entity>>()
1129
}
1130
1131
assert_eq!(
1132
get_filtered::<Changed<SparseStored>>(&mut world),
1133
[e1, e3].into_iter().collect::<HashSet<_>>()
1134
);
1135
1136
// ensure changing an entity's archetypes also moves its changed state
1137
world.entity_mut(e1).insert(C);
1138
1139
assert_eq!(get_filtered::<Changed<SparseStored>>(&mut world), [e3, e1].into_iter().collect::<HashSet<_>>(), "changed entities list should not change (although the order will due to archetype moves)");
1140
1141
// spawning a new SparseStored entity should not change existing changed state
1142
world.entity_mut(e1).insert(SparseStored(0));
1143
assert_eq!(
1144
get_filtered::<Changed<SparseStored>>(&mut world),
1145
[e3, e1].into_iter().collect::<HashSet<_>>(),
1146
"changed entities list should not change"
1147
);
1148
1149
// removing an unchanged entity should not change changed state
1150
assert!(world.despawn(e2));
1151
assert_eq!(
1152
get_filtered::<Changed<SparseStored>>(&mut world),
1153
[e3, e1].into_iter().collect::<HashSet<_>>(),
1154
"changed entities list should not change"
1155
);
1156
1157
// removing a changed entity should remove it from enumeration
1158
assert!(world.despawn(e1));
1159
assert_eq!(
1160
get_filtered::<Changed<SparseStored>>(&mut world),
1161
[e3].into_iter().collect::<HashSet<_>>(),
1162
"e1 should no longer be returned"
1163
);
1164
1165
world.clear_trackers();
1166
1167
assert!(get_filtered::<Changed<SparseStored>>(&mut world).is_empty());
1168
1169
let e4 = world.spawn_empty().id();
1170
1171
world.entity_mut(e4).insert(SparseStored(0));
1172
assert_eq!(
1173
get_filtered::<Changed<SparseStored>>(&mut world),
1174
[e4].into_iter().collect::<HashSet<_>>()
1175
);
1176
assert_eq!(
1177
get_filtered::<Added<SparseStored>>(&mut world),
1178
[e4].into_iter().collect::<HashSet<_>>()
1179
);
1180
1181
world.entity_mut(e4).insert(A(1));
1182
assert_eq!(
1183
get_filtered::<Changed<SparseStored>>(&mut world),
1184
[e4].into_iter().collect::<HashSet<_>>()
1185
);
1186
1187
world.clear_trackers();
1188
1189
// ensure inserting multiple components set changed state for all components and set added
1190
// state for non existing components even when changing archetype.
1191
world.entity_mut(e4).insert(SparseStored(0));
1192
1193
assert!(get_filtered::<Added<SparseStored>>(&mut world).is_empty());
1194
assert_eq!(
1195
get_filtered::<Changed<SparseStored>>(&mut world),
1196
[e4].into_iter().collect::<HashSet<_>>()
1197
);
1198
}
1199
1200
#[test]
1201
fn empty_spawn() {
1202
let mut world = World::default();
1203
let e = world.spawn_empty().id();
1204
let mut e_mut = world.entity_mut(e);
1205
e_mut.insert(A(0));
1206
assert_eq!(e_mut.get::<A>().unwrap(), &A(0));
1207
}
1208
1209
#[test]
1210
fn reserve_and_spawn() {
1211
let mut world = World::default();
1212
let e = world.entities().reserve_entity();
1213
world.flush_entities();
1214
let mut e_mut = world.entity_mut(e);
1215
e_mut.insert(A(0));
1216
assert_eq!(e_mut.get::<A>().unwrap(), &A(0));
1217
}
1218
1219
#[test]
1220
fn changed_query() {
1221
let mut world = World::default();
1222
let e1 = world.spawn((A(0), B(0))).id();
1223
1224
fn get_changed(world: &mut World) -> Vec<Entity> {
1225
world
1226
.query_filtered::<Entity, Changed<A>>()
1227
.iter(world)
1228
.collect::<Vec<Entity>>()
1229
}
1230
assert_eq!(get_changed(&mut world), vec![e1]);
1231
world.clear_trackers();
1232
assert_eq!(get_changed(&mut world), vec![]);
1233
*world.get_mut(e1).unwrap() = A(1);
1234
assert_eq!(get_changed(&mut world), vec![e1]);
1235
}
1236
1237
#[test]
1238
fn resource() {
1239
use crate::resource::Resource;
1240
1241
#[derive(Resource, PartialEq, Debug)]
1242
struct Num(i32);
1243
1244
#[derive(Resource, PartialEq, Debug)]
1245
struct BigNum(u64);
1246
1247
let mut world = World::default();
1248
assert!(world.get_resource::<Num>().is_none());
1249
assert!(!world.contains_resource::<Num>());
1250
assert!(!world.is_resource_added::<Num>());
1251
assert!(!world.is_resource_changed::<Num>());
1252
1253
world.insert_resource(Num(123));
1254
let resource_id = world
1255
.components()
1256
.get_resource_id(TypeId::of::<Num>())
1257
.unwrap();
1258
1259
assert_eq!(world.resource::<Num>().0, 123);
1260
assert!(world.contains_resource::<Num>());
1261
assert!(world.is_resource_added::<Num>());
1262
assert!(world.is_resource_changed::<Num>());
1263
1264
world.insert_resource(BigNum(456));
1265
assert_eq!(world.resource::<BigNum>().0, 456u64);
1266
1267
world.insert_resource(BigNum(789));
1268
assert_eq!(world.resource::<BigNum>().0, 789);
1269
1270
{
1271
let mut value = world.resource_mut::<BigNum>();
1272
assert_eq!(value.0, 789);
1273
value.0 = 10;
1274
}
1275
1276
assert_eq!(
1277
world.resource::<BigNum>().0,
1278
10,
1279
"resource changes are preserved"
1280
);
1281
1282
assert_eq!(
1283
world.remove_resource::<BigNum>(),
1284
Some(BigNum(10)),
1285
"removed resource has the correct value"
1286
);
1287
assert_eq!(
1288
world.get_resource::<BigNum>(),
1289
None,
1290
"removed resource no longer exists"
1291
);
1292
assert_eq!(
1293
world.remove_resource::<BigNum>(),
1294
None,
1295
"double remove returns nothing"
1296
);
1297
1298
world.insert_resource(BigNum(1));
1299
assert_eq!(
1300
world.get_resource::<BigNum>(),
1301
Some(&BigNum(1)),
1302
"re-inserting resources works"
1303
);
1304
1305
assert_eq!(
1306
world.get_resource::<Num>(),
1307
Some(&Num(123)),
1308
"other resources are unaffected"
1309
);
1310
1311
let current_resource_id = world
1312
.components()
1313
.get_resource_id(TypeId::of::<Num>())
1314
.unwrap();
1315
assert_eq!(
1316
resource_id, current_resource_id,
1317
"resource id does not change after removing / re-adding"
1318
);
1319
}
1320
1321
#[test]
1322
fn remove() {
1323
let mut world = World::default();
1324
let e1 = world.spawn((A(1), B(1), TableStored("a"))).id();
1325
1326
let mut e = world.entity_mut(e1);
1327
assert_eq!(e.get::<TableStored>(), Some(&TableStored("a")));
1328
assert_eq!(e.get::<A>(), Some(&A(1)));
1329
assert_eq!(e.get::<B>(), Some(&B(1)));
1330
assert_eq!(
1331
e.get::<C>(),
1332
None,
1333
"C is not in the entity, so it should not exist"
1334
);
1335
1336
e.remove::<(A, B, C)>();
1337
assert_eq!(
1338
e.get::<TableStored>(),
1339
Some(&TableStored("a")),
1340
"TableStored is not in the removed bundle, so it should exist"
1341
);
1342
assert_eq!(
1343
e.get::<A>(),
1344
None,
1345
"Num is in the removed bundle, so it should not exist"
1346
);
1347
assert_eq!(
1348
e.get::<B>(),
1349
None,
1350
"f64 is in the removed bundle, so it should not exist"
1351
);
1352
assert_eq!(
1353
e.get::<C>(),
1354
None,
1355
"usize is in the removed bundle, so it should not exist"
1356
);
1357
}
1358
1359
#[test]
1360
fn take() {
1361
let mut world = World::default();
1362
world.spawn((A(1), B(1), TableStored("1")));
1363
let e2 = world.spawn((A(2), B(2), TableStored("2"))).id();
1364
world.spawn((A(3), B(3), TableStored("3")));
1365
1366
let mut query = world.query::<(&B, &TableStored)>();
1367
let results = query
1368
.iter(&world)
1369
.map(|(a, b)| (a.0, b.0))
1370
.collect::<HashSet<_>>();
1371
assert_eq!(
1372
results,
1373
[(1, "1"), (2, "2"), (3, "3"),]
1374
.into_iter()
1375
.collect::<HashSet<_>>()
1376
);
1377
1378
let removed_bundle = world.entity_mut(e2).take::<(B, TableStored)>().unwrap();
1379
assert_eq!(removed_bundle, (B(2), TableStored("2")));
1380
1381
let results = query
1382
.iter(&world)
1383
.map(|(a, b)| (a.0, b.0))
1384
.collect::<HashSet<_>>();
1385
assert_eq!(
1386
results,
1387
[(1, "1"), (3, "3"),].into_iter().collect::<HashSet<_>>()
1388
);
1389
1390
let mut a_query = world.query::<&A>();
1391
let results = a_query.iter(&world).map(|a| a.0).collect::<HashSet<_>>();
1392
assert_eq!(results, [1, 3, 2].into_iter().collect::<HashSet<_>>());
1393
1394
let entity_ref = world.entity(e2);
1395
assert_eq!(
1396
entity_ref.get::<A>(),
1397
Some(&A(2)),
1398
"A is not in the removed bundle, so it should exist"
1399
);
1400
assert_eq!(
1401
entity_ref.get::<B>(),
1402
None,
1403
"B is in the removed bundle, so it should not exist"
1404
);
1405
assert_eq!(
1406
entity_ref.get::<TableStored>(),
1407
None,
1408
"TableStored is in the removed bundle, so it should not exist"
1409
);
1410
}
1411
1412
#[test]
1413
fn non_send_resource() {
1414
let mut world = World::default();
1415
world.insert_non_send_resource(123i32);
1416
world.insert_non_send_resource(456i64);
1417
assert_eq!(*world.non_send_resource::<i32>(), 123);
1418
assert_eq!(*world.non_send_resource_mut::<i64>(), 456);
1419
}
1420
1421
#[test]
1422
fn non_send_resource_points_to_distinct_data() {
1423
let mut world = World::default();
1424
world.insert_resource(A(123));
1425
world.insert_non_send_resource(A(456));
1426
assert_eq!(*world.resource::<A>(), A(123));
1427
assert_eq!(*world.non_send_resource::<A>(), A(456));
1428
}
1429
1430
#[test]
1431
#[should_panic]
1432
fn non_send_resource_panic() {
1433
let mut world = World::default();
1434
world.insert_non_send_resource(0i32);
1435
std::thread::spawn(move || {
1436
let _ = world.non_send_resource_mut::<i32>();
1437
})
1438
.join()
1439
.unwrap();
1440
}
1441
1442
#[test]
1443
fn exact_size_query() {
1444
let mut world = World::default();
1445
world.spawn((A(0), B(0)));
1446
world.spawn((A(0), B(0)));
1447
world.spawn((A(0), B(0), C));
1448
world.spawn(C);
1449
1450
let mut query = world.query::<(&A, &B)>();
1451
assert_eq!(query.iter(&world).len(), 3);
1452
}
1453
1454
#[test]
1455
#[should_panic]
1456
fn duplicate_components_panic() {
1457
let mut world = World::new();
1458
world.spawn((A(1), A(2)));
1459
}
1460
1461
#[test]
1462
#[should_panic]
1463
fn ref_and_mut_query_panic() {
1464
let mut world = World::new();
1465
world.query::<(&A, &mut A)>();
1466
}
1467
1468
#[test]
1469
#[should_panic]
1470
fn entity_ref_and_mut_query_panic() {
1471
let mut world = World::new();
1472
world.query::<(EntityRef, &mut A)>();
1473
}
1474
1475
#[test]
1476
#[should_panic]
1477
fn mut_and_ref_query_panic() {
1478
let mut world = World::new();
1479
world.query::<(&mut A, &A)>();
1480
}
1481
1482
#[test]
1483
#[should_panic]
1484
fn mut_and_entity_ref_query_panic() {
1485
let mut world = World::new();
1486
world.query::<(&mut A, EntityRef)>();
1487
}
1488
1489
#[test]
1490
#[should_panic]
1491
fn entity_ref_and_entity_mut_query_panic() {
1492
let mut world = World::new();
1493
world.query::<(EntityRef, EntityMut)>();
1494
}
1495
1496
#[test]
1497
#[should_panic]
1498
fn entity_mut_and_entity_mut_query_panic() {
1499
let mut world = World::new();
1500
world.query::<(EntityMut, EntityMut)>();
1501
}
1502
1503
#[test]
1504
fn entity_ref_and_entity_ref_query_no_panic() {
1505
let mut world = World::new();
1506
world.query::<(EntityRef, EntityRef)>();
1507
}
1508
1509
#[test]
1510
#[should_panic]
1511
fn mut_and_mut_query_panic() {
1512
let mut world = World::new();
1513
world.query::<(&mut A, &mut A)>();
1514
}
1515
1516
#[test]
1517
#[should_panic]
1518
fn multiple_worlds_same_query_iter() {
1519
let mut world_a = World::new();
1520
let world_b = World::new();
1521
let mut query = world_a.query::<&A>();
1522
query.iter(&world_a);
1523
query.iter(&world_b);
1524
}
1525
1526
#[test]
1527
fn query_filters_dont_collide_with_fetches() {
1528
let mut world = World::new();
1529
world.query_filtered::<&mut A, Changed<A>>();
1530
}
1531
1532
#[test]
1533
fn filtered_query_access() {
1534
let mut world = World::new();
1535
// We remove entity disabling so it doesn't affect our query filters
1536
world.remove_resource::<DefaultQueryFilters>();
1537
let query = world.query_filtered::<&mut A, Changed<B>>();
1538
1539
let mut expected = FilteredAccess::default();
1540
let a_id = world.components.get_id(TypeId::of::<A>()).unwrap();
1541
let b_id = world.components.get_id(TypeId::of::<B>()).unwrap();
1542
expected.add_component_write(a_id);
1543
expected.add_component_read(b_id);
1544
assert!(
1545
query.component_access.eq(&expected),
1546
"ComponentId access from query fetch and query filter should be combined"
1547
);
1548
}
1549
1550
#[test]
1551
#[should_panic]
1552
fn multiple_worlds_same_query_get() {
1553
let mut world_a = World::new();
1554
let world_b = World::new();
1555
let mut query = world_a.query::<&A>();
1556
let _ = query.get(&world_a, Entity::from_raw_u32(0).unwrap());
1557
let _ = query.get(&world_b, Entity::from_raw_u32(0).unwrap());
1558
}
1559
1560
#[test]
1561
#[should_panic]
1562
fn multiple_worlds_same_query_for_each() {
1563
let mut world_a = World::new();
1564
let world_b = World::new();
1565
let mut query = world_a.query::<&A>();
1566
query.iter(&world_a).for_each(|_| {});
1567
query.iter(&world_b).for_each(|_| {});
1568
}
1569
1570
#[test]
1571
fn resource_scope() {
1572
let mut world = World::default();
1573
assert!(world.try_resource_scope::<A, _>(|_, _| {}).is_none());
1574
world.insert_resource(A(0));
1575
world.resource_scope(|world: &mut World, mut value: Mut<A>| {
1576
value.0 += 1;
1577
assert!(!world.contains_resource::<A>());
1578
});
1579
assert_eq!(world.resource::<A>().0, 1);
1580
}
1581
1582
#[test]
1583
#[should_panic]
1584
fn non_send_resource_drop_from_different_thread() {
1585
let mut world = World::default();
1586
world.insert_non_send_resource(NonSendA::default());
1587
1588
let thread = std::thread::spawn(move || {
1589
// Dropping the non-send resource on a different thread
1590
// Should result in a panic
1591
drop(world);
1592
});
1593
1594
if let Err(err) = thread.join() {
1595
std::panic::resume_unwind(err);
1596
}
1597
}
1598
1599
#[test]
1600
fn non_send_resource_drop_from_same_thread() {
1601
let mut world = World::default();
1602
world.insert_non_send_resource(NonSendA::default());
1603
drop(world);
1604
}
1605
1606
#[test]
1607
fn insert_overwrite_drop() {
1608
let (dropck1, dropped1) = DropCk::new_pair();
1609
let (dropck2, dropped2) = DropCk::new_pair();
1610
let mut world = World::default();
1611
world.spawn(dropck1).insert(dropck2);
1612
assert_eq!(dropped1.load(Ordering::Relaxed), 1);
1613
assert_eq!(dropped2.load(Ordering::Relaxed), 0);
1614
drop(world);
1615
assert_eq!(dropped1.load(Ordering::Relaxed), 1);
1616
assert_eq!(dropped2.load(Ordering::Relaxed), 1);
1617
}
1618
1619
#[test]
1620
fn insert_overwrite_drop_sparse() {
1621
let (dropck1, dropped1) = DropCk::new_pair();
1622
let (dropck2, dropped2) = DropCk::new_pair();
1623
let mut world = World::default();
1624
1625
world
1626
.spawn(DropCkSparse(dropck1))
1627
.insert(DropCkSparse(dropck2));
1628
assert_eq!(dropped1.load(Ordering::Relaxed), 1);
1629
assert_eq!(dropped2.load(Ordering::Relaxed), 0);
1630
drop(world);
1631
assert_eq!(dropped1.load(Ordering::Relaxed), 1);
1632
assert_eq!(dropped2.load(Ordering::Relaxed), 1);
1633
}
1634
1635
#[test]
1636
fn clear_entities() {
1637
let mut world = World::default();
1638
1639
world.insert_resource(A(0));
1640
world.spawn(A(1));
1641
world.spawn(SparseStored(1));
1642
1643
let mut q1 = world.query::<&A>();
1644
let mut q2 = world.query::<&SparseStored>();
1645
let mut q3 = world.query::<()>();
1646
1647
assert_eq!(q1.query(&world).count(), 1);
1648
assert_eq!(q2.query(&world).count(), 1);
1649
assert_eq!(q3.query(&world).count(), 2);
1650
1651
world.clear_entities();
1652
1653
assert_eq!(
1654
q1.query(&world).count(),
1655
0,
1656
"world should not contain table components"
1657
);
1658
assert_eq!(
1659
q2.query(&world).count(),
1660
0,
1661
"world should not contain sparse set components"
1662
);
1663
assert_eq!(
1664
q3.query(&world).count(),
1665
0,
1666
"world should not have any entities"
1667
);
1668
assert_eq!(
1669
world.resource::<A>().0,
1670
0,
1671
"world should still contain resources"
1672
);
1673
}
1674
1675
#[test]
1676
fn test_is_archetypal_size_hints() {
1677
let mut world = World::default();
1678
macro_rules! query_min_size {
1679
($query:ty, $filter:ty) => {
1680
world
1681
.query_filtered::<$query, $filter>()
1682
.iter(&world)
1683
.size_hint()
1684
.0
1685
};
1686
}
1687
1688
world.spawn((A(1), B(1), C));
1689
world.spawn((A(1), C));
1690
world.spawn((A(1), B(1)));
1691
world.spawn((B(1), C));
1692
world.spawn(A(1));
1693
world.spawn(C);
1694
assert_eq!(2, query_min_size![(), (With<A>, Without<B>)]);
1695
assert_eq!(3, query_min_size![&B, Or<(With<A>, With<C>)>]);
1696
assert_eq!(1, query_min_size![&B, (With<A>, With<C>)]);
1697
assert_eq!(1, query_min_size![(&A, &B), With<C>]);
1698
assert_eq!(4, query_min_size![&A, ()], "Simple Archetypal");
1699
assert_eq!(4, query_min_size![Ref<A>, ()]);
1700
// All the following should set minimum size to 0, as it's impossible to predict
1701
// how many entities the filters will trim.
1702
assert_eq!(0, query_min_size![(), Added<A>], "Simple Added");
1703
assert_eq!(0, query_min_size![(), Changed<A>], "Simple Changed");
1704
assert_eq!(0, query_min_size![(&A, &B), Changed<A>]);
1705
assert_eq!(0, query_min_size![&A, (Changed<A>, With<B>)]);
1706
assert_eq!(0, query_min_size![(&A, &B), Or<(Changed<A>, Changed<B>)>]);
1707
}
1708
1709
#[test]
1710
fn insert_batch() {
1711
let mut world = World::default();
1712
let e0 = world.spawn(A(0)).id();
1713
let e1 = world.spawn(B(0)).id();
1714
1715
let values = vec![(e0, (A(1), B(0))), (e1, (A(0), B(1)))];
1716
1717
world.insert_batch(values);
1718
1719
assert_eq!(
1720
world.get::<A>(e0),
1721
Some(&A(1)),
1722
"first entity's A component should have been replaced"
1723
);
1724
assert_eq!(
1725
world.get::<B>(e0),
1726
Some(&B(0)),
1727
"first entity should have received B component"
1728
);
1729
assert_eq!(
1730
world.get::<A>(e1),
1731
Some(&A(0)),
1732
"second entity should have received A component"
1733
);
1734
assert_eq!(
1735
world.get::<B>(e1),
1736
Some(&B(1)),
1737
"second entity's B component should have been replaced"
1738
);
1739
}
1740
1741
#[test]
1742
fn insert_batch_same_archetype() {
1743
let mut world = World::default();
1744
let e0 = world.spawn((A(0), B(0))).id();
1745
let e1 = world.spawn((A(0), B(0))).id();
1746
let e2 = world.spawn(B(0)).id();
1747
1748
let values = vec![(e0, (B(1), C)), (e1, (B(2), C)), (e2, (B(3), C))];
1749
1750
world.insert_batch(values);
1751
let mut query = world.query::<(Option<&A>, &B, &C)>();
1752
let component_values = query.get_many(&world, [e0, e1, e2]).unwrap();
1753
1754
assert_eq!(
1755
component_values,
1756
[(Some(&A(0)), &B(1), &C), (Some(&A(0)), &B(2), &C), (None, &B(3), &C)],
1757
"all entities should have had their B component replaced, received C component, and had their A component (or lack thereof) unchanged"
1758
);
1759
}
1760
1761
#[test]
1762
fn insert_batch_if_new() {
1763
let mut world = World::default();
1764
let e0 = world.spawn(A(0)).id();
1765
let e1 = world.spawn(B(0)).id();
1766
1767
let values = vec![(e0, (A(1), B(0))), (e1, (A(0), B(1)))];
1768
1769
world.insert_batch_if_new(values);
1770
1771
assert_eq!(
1772
world.get::<A>(e0),
1773
Some(&A(0)),
1774
"first entity's A component should not have been replaced"
1775
);
1776
assert_eq!(
1777
world.get::<B>(e0),
1778
Some(&B(0)),
1779
"first entity should have received B component"
1780
);
1781
assert_eq!(
1782
world.get::<A>(e1),
1783
Some(&A(0)),
1784
"second entity should have received A component"
1785
);
1786
assert_eq!(
1787
world.get::<B>(e1),
1788
Some(&B(0)),
1789
"second entity's B component should not have been replaced"
1790
);
1791
}
1792
1793
#[test]
1794
fn try_insert_batch() {
1795
let mut world = World::default();
1796
let e0 = world.spawn(A(0)).id();
1797
let e1 = Entity::from_raw_u32(1).unwrap();
1798
1799
let values = vec![(e0, (A(1), B(0))), (e1, (A(0), B(1)))];
1800
1801
let error = world.try_insert_batch(values).unwrap_err();
1802
1803
assert_eq!(e1, error.entities[0]);
1804
1805
assert_eq!(
1806
world.get::<A>(e0),
1807
Some(&A(1)),
1808
"first entity's A component should have been replaced"
1809
);
1810
assert_eq!(
1811
world.get::<B>(e0),
1812
Some(&B(0)),
1813
"first entity should have received B component"
1814
);
1815
}
1816
1817
#[test]
1818
fn try_insert_batch_if_new() {
1819
let mut world = World::default();
1820
let e0 = world.spawn(A(0)).id();
1821
let e1 = Entity::from_raw_u32(1).unwrap();
1822
1823
let values = vec![(e0, (A(1), B(0))), (e1, (A(0), B(1)))];
1824
1825
let error = world.try_insert_batch_if_new(values).unwrap_err();
1826
1827
assert_eq!(e1, error.entities[0]);
1828
1829
assert_eq!(
1830
world.get::<A>(e0),
1831
Some(&A(0)),
1832
"first entity's A component should not have been replaced"
1833
);
1834
assert_eq!(
1835
world.get::<B>(e0),
1836
Some(&B(0)),
1837
"first entity should have received B component"
1838
);
1839
}
1840
1841
#[derive(Default)]
1842
struct CaptureMapper(Vec<Entity>);
1843
impl EntityMapper for CaptureMapper {
1844
fn get_mapped(&mut self, source: Entity) -> Entity {
1845
self.0.push(source);
1846
source
1847
}
1848
1849
fn set_mapped(&mut self, _source: Entity, _target: Entity) {}
1850
}
1851
1852
#[test]
1853
fn map_struct_entities() {
1854
#[derive(Component)]
1855
#[expect(
1856
unused,
1857
reason = "extra fields are used to ensure the derive works properly"
1858
)]
1859
struct Foo(usize, #[entities] Entity);
1860
1861
#[derive(Component)]
1862
#[expect(
1863
unused,
1864
reason = "extra fields are used to ensure the derive works properly"
1865
)]
1866
struct Bar {
1867
#[entities]
1868
a: Entity,
1869
b: usize,
1870
#[entities]
1871
c: Vec<Entity>,
1872
}
1873
1874
let mut world = World::new();
1875
let e1 = world.spawn_empty().id();
1876
let e2 = world.spawn_empty().id();
1877
let e3 = world.spawn_empty().id();
1878
1879
let mut foo = Foo(1, e1);
1880
let mut mapper = CaptureMapper::default();
1881
Component::map_entities(&mut foo, &mut mapper);
1882
assert_eq!(&mapper.0, &[e1]);
1883
1884
let mut bar = Bar {
1885
a: e1,
1886
b: 1,
1887
c: vec![e2, e3],
1888
};
1889
let mut mapper = CaptureMapper::default();
1890
Component::map_entities(&mut bar, &mut mapper);
1891
assert_eq!(&mapper.0, &[e1, e2, e3]);
1892
}
1893
1894
#[test]
1895
fn map_enum_entities() {
1896
#[derive(Component)]
1897
#[expect(
1898
unused,
1899
reason = "extra fields are used to ensure the derive works properly"
1900
)]
1901
enum Foo {
1902
Bar(usize, #[entities] Entity),
1903
Baz {
1904
#[entities]
1905
a: Entity,
1906
b: usize,
1907
#[entities]
1908
c: Vec<Entity>,
1909
},
1910
}
1911
1912
let mut world = World::new();
1913
let e1 = world.spawn_empty().id();
1914
let e2 = world.spawn_empty().id();
1915
let e3 = world.spawn_empty().id();
1916
1917
let mut foo = Foo::Bar(1, e1);
1918
let mut mapper = CaptureMapper::default();
1919
Component::map_entities(&mut foo, &mut mapper);
1920
assert_eq!(&mapper.0, &[e1]);
1921
1922
let mut foo = Foo::Baz {
1923
a: e1,
1924
b: 1,
1925
c: vec![e2, e3],
1926
};
1927
let mut mapper = CaptureMapper::default();
1928
Component::map_entities(&mut foo, &mut mapper);
1929
assert_eq!(&mapper.0, &[e1, e2, e3]);
1930
}
1931
1932
#[expect(
1933
dead_code,
1934
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
1935
)]
1936
#[derive(Component)]
1937
struct ComponentA(u32);
1938
1939
#[expect(
1940
dead_code,
1941
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
1942
)]
1943
#[derive(Component)]
1944
struct ComponentB(u32);
1945
1946
#[derive(Bundle)]
1947
struct Simple(ComponentA);
1948
1949
#[expect(
1950
dead_code,
1951
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
1952
)]
1953
#[derive(Bundle)]
1954
struct Tuple(Simple, ComponentB);
1955
1956
#[expect(
1957
dead_code,
1958
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
1959
)]
1960
#[derive(Bundle)]
1961
struct Record {
1962
field0: Simple,
1963
field1: ComponentB,
1964
}
1965
1966
#[expect(
1967
dead_code,
1968
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
1969
)]
1970
#[derive(Component)]
1971
struct MyEntities {
1972
#[entities]
1973
entities: Vec<Entity>,
1974
#[entities]
1975
another_one: Entity,
1976
#[entities]
1977
maybe_entity: Option<Entity>,
1978
something_else: String,
1979
}
1980
1981
#[expect(
1982
dead_code,
1983
reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
1984
)]
1985
#[derive(Component)]
1986
struct MyEntitiesTuple(#[entities] Vec<Entity>, #[entities] Entity, usize);
1987
1988
#[test]
1989
fn clone_entities() {
1990
use crate::entity::{ComponentCloneCtx, SourceComponent};
1991
1992
#[expect(
1993
dead_code,
1994
reason = "This struct is used as a compilation test to test the derive macros, and as such this field is intentionally never used."
1995
)]
1996
#[derive(Component)]
1997
#[component(clone_behavior = Ignore)]
1998
struct IgnoreClone;
1999
2000
#[expect(
2001
dead_code,
2002
reason = "This struct is used as a compilation test to test the derive macros, and as such this field is intentionally never used."
2003
)]
2004
#[derive(Component)]
2005
#[component(clone_behavior = Default)]
2006
struct DefaultClone;
2007
2008
#[expect(
2009
dead_code,
2010
reason = "This struct is used as a compilation test to test the derive macros, and as such this field is intentionally never used."
2011
)]
2012
#[derive(Component)]
2013
#[component(clone_behavior = Custom(custom_clone))]
2014
struct CustomClone;
2015
2016
#[expect(
2017
dead_code,
2018
reason = "This struct is used as a compilation test to test the derive macros, and as such this field is intentionally never used."
2019
)]
2020
#[derive(Component, Clone)]
2021
#[component(clone_behavior = clone::<Self>())]
2022
struct CloneFunction;
2023
2024
#[expect(
2025
dead_code,
2026
reason = "This struct is used as a compilation test to test the derive macros, and as such this field is intentionally never used."
2027
)]
2028
fn custom_clone(_source: &SourceComponent, _ctx: &mut ComponentCloneCtx) {}
2029
}
2030
2031
#[test]
2032
fn queue_register_component_toctou() {
2033
for _ in 0..1000 {
2034
let w = World::new();
2035
2036
std::thread::scope(|s| {
2037
let c1 = s.spawn(|| w.components_queue().queue_register_component::<A>());
2038
let c2 = s.spawn(|| w.components_queue().queue_register_component::<A>());
2039
assert_eq!(c1.join().unwrap(), c2.join().unwrap());
2040
});
2041
}
2042
}
2043
}
2044
2045