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