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