unlit_ecs/world.rs
1//! The world: entities, their components, and the scopes they live in.
2//!
3//! Components live in `UnsafeCell`s so that a shared `&World` can reach them,
4//! and a borrow ledger written through that same shared reference catches two
5//! access paths reaching one value when at least one of them writes. The world
6//! is therefore `!Send`: it stays on the thread that created it, which is where
7//! a renderer or any other `!Send` state lives.
8//!
9//! Reading and writing components needs only `&World`. Structural changes --
10//! spawning and despawning -- need `&mut World`. A callback that only has a shared world can queue those
11//! changes instead with [`crate::Commands`] and apply them later with
12//! [`World::apply`].
13//!
14//! Every entity lives in a scope, and a scope is another entity: the one the
15//! world's tree says it lives in. The world therefore holds a tree, and the
16//! entry points that read or write it are scopes of a scope rather than
17//! methods on the world -- [`Scope`] and [`ScopeMut`]. A scope sees
18//! its own subtree and nothing beside it; only `&World` reaches the root.
19//!
20//! An entity's components are fixed when it is spawned; there is no way to add
21//! or remove one later. To change the set of components, despawn the entity
22//! and spawn a new one.
23//!
24//! A borrow conflict is a panic, not a compile error: two claims the ledger
25//! cannot share — a shared claim still held while a write asks for the same
26//! component, or the same component fetched as `&mut` twice in one query —
27//! report the component's name and both claim sites, then stop. This is the
28//! trade for not doing access analysis. An optional component is optional only
29//! about the component being absent: a conflict over one the row does carry
30//! panics as well.
31
32use core::any::TypeId;
33use core::cell::{Ref, RefCell, RefMut};
34use std::collections::VecDeque;
35
36use crate::archetype::{Archetype, Archetypes};
37use crate::borrow::{BorrowLedger, Rows};
38use crate::bundle::{Bundle, BundleComponent, DynamicBundle};
39use crate::column::AnyColumn;
40use crate::command::Command;
41use crate::entity::{Entities, Entity, Location};
42use crate::error::EntityAccessError;
43use crate::hash::TypeIdHashMap;
44use crate::lifecycle::{Lifecycle, LifecycleCallback};
45use crate::query::Mode;
46use crate::scope::ScopeTree;
47use crate::view::{Scope, ScopeMut};
48
49/// Entities and their components.
50pub struct World {
51 /// Where each handle lives, and the allocator behind it.
52 ///
53 /// Still a cell: [`World::reserve_entity`] hands out a handle through
54 /// `&World` so that [`Commands::spawn`](crate::Commands::spawn) can answer one
55 /// before the queue is applied, and a reservation is a real allocation, not
56 /// a queued intent. Everything else that touches this table runs under
57 /// `&mut World`, so the two never overlap.
58 entities: RefCell<Entities>,
59 archetypes: Archetypes,
60 /// Column constructors, one per component type that ever entered the world.
61 ctors: TypeIdHashMap<fn() -> Box<dyn AnyColumn>>,
62 /// The name of every component type that ever entered the world.
63 names: TypeIdHashMap<&'static str>,
64 /// Structural changes waiting for the next [`World::apply`].
65 ///
66 /// A cell for the same reason: a command is queued from a callback that
67 /// only holds `&World`.
68 commands: RefCell<VecDeque<Box<dyn Command>>>,
69 /// Where every live entity lives.
70 ///
71 /// Not a cell: every write to it happens under `&mut World`, and a reader
72 /// borrowing it from `&World` keeps that shared borrow alive, which is what
73 /// excludes one. The visibility walk reads it on every row, so the absence of
74 /// a runtime flag there is the point.
75 tree: ScopeTree,
76 /// Who holds which component values.
77 ///
78 /// A cell because a claim is registered by a query constructed from `&World`
79 /// and dropped by its holder's `Drop`, neither of which has the world
80 /// mutably.
81 borrow: RefCell<BorrowLedger>,
82 /// The entity that owns the world, whose scope sees everything.
83 root: Entity,
84 /// The entity whose subtree every scope sees.
85 shared: Entity,
86 /// The archetype holding the two scaffolding entities.
87 ///
88 /// They are the only entities that exist without being content, so a scope
89 /// that counts rows has to know where they are. They take the first
90 /// [`World::SCAFFOLDING_ROWS`] rows of it.
91 scaffolding: u32,
92}
93
94/// The exclusive borrow of a world's command queue.
95pub(crate) type CommandsGuard<'w> = RefMut<'w, VecDeque<Box<dyn Command>>>;
96
97impl Default for World {
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103impl World {
104 /// How many rows the two scaffolding entities take.
105 ///
106 /// [`World::new`] pushes both before any caller can spawn, and a removal only
107 /// ever moves the last row of an archetype into the hole it leaves, so the
108 /// pair stays at the front for the world's whole life.
109 const SCAFFOLDING_ROWS: usize = 2;
110
111 /// A world holding its root and shared scope, and nothing else.
112 ///
113 /// Both are ordinary entities: they are addressable, carry components and
114 /// can be opened as scopes, and they are what a shared resource hangs from.
115 /// Neither is counted, queried, despawned or linked; see [`Scope::len`],
116 /// which reports the entities a scope sees with the pair left out.
117 pub fn new() -> Self {
118 let mut world = Self {
119 entities: RefCell::new(Entities::default()),
120 archetypes: Archetypes::new(),
121 ctors: TypeIdHashMap::default(),
122 names: TypeIdHashMap::default(),
123 commands: RefCell::new(VecDeque::new()),
124 tree: ScopeTree::default(),
125 borrow: RefCell::new(BorrowLedger::default()),
126 // Both are overwritten below, before the world leaves this
127 // function and anything can read them.
128 root: Entity::from_raw(0, 0),
129 shared: Entity::from_raw(0, 0),
130 scaffolding: 0,
131 };
132 // The root's scope is itself, which is where walking up the tree stops.
133 // It is recorded before the shared scope is inserted, because that one
134 // hangs from it. Neither goes through the spawn path, which reads the
135 // root that is being written here.
136 let root = world.entities_write().alloc("root");
137 world.root = root;
138 world.insert_row(root, root, crate::DynamicBundle::new());
139 let shared = world.entities_write().alloc("shared");
140 world.shared = shared;
141 world.insert_row(shared, root, crate::DynamicBundle::new());
142 world.scaffolding = world
143 .location(root)
144 .expect("the root has a row")
145 .archetype();
146 debug_assert_eq!(
147 world.archetypes().as_slice()[world.scaffolding as usize].entities(),
148 &[root, shared][..],
149 "the scaffolding takes the first rows of its archetype",
150 );
151 world
152 }
153
154 // -- the tree ----------------------------------------------------------
155
156 /// The entity that owns the world, whose scope sees everything.
157 #[must_use]
158 pub fn root(&self) -> Entity {
159 self.root
160 }
161
162 /// The entity whose subtree every scope sees.
163 #[must_use]
164 pub fn shared(&self) -> Entity {
165 self.shared
166 }
167
168 /// Whether `entity` is in the shared subtree, itself included.
169 #[must_use]
170 pub fn is_shared(&self, entity: Entity) -> bool {
171 entity == self.shared || self.is_descendant(self.shared, entity)
172 }
173
174 /// Whether `entity` is one of the tree's two scaffolding entities.
175 ///
176 /// This is narrower than [`World::is_shared`], which covers the whole
177 /// shared subtree: the entities a caller spawns there are content, and a
178 /// scope counts and queries them like any other.
179 #[must_use]
180 pub fn is_scaffolding(&self, entity: Entity) -> bool {
181 entity == self.root || entity == self.shared
182 }
183
184 /// Whether `entity` is strictly below `ancestor` in the tree.
185 #[must_use]
186 pub fn is_descendant(&self, ancestor: Entity, entity: Entity) -> bool {
187 self.tree.is_descendant(ancestor, entity)
188 }
189
190 /// Whether a scope of `caller` sees `candidate`.
191 ///
192 /// The shared subtree reaches every scope, the root sees everything, and a
193 /// scope sees itself and everything below it. A handle that is not alive is
194 /// visible from nowhere, the root included: seeing a place is not the same
195 /// as there being something in it.
196 #[must_use]
197 pub fn visible(&self, caller: Entity, candidate: Entity) -> bool {
198 if !self.entities_read().contains(candidate) {
199 return false;
200 }
201 // The root is the hot case: it sees everything, so it is answered
202 // before the parent-chain walks below.
203 caller == self.root
204 || candidate == caller
205 || self.is_shared(candidate)
206 || self.is_descendant(caller, candidate)
207 }
208
209 /// Whether a scope of `caller` may despawn or relink `entity`.
210 ///
211 /// Ownership is stricter than visibility: the shared subtree is readable
212 /// from everywhere but only the root may move or remove it.
213 #[must_use]
214 pub fn owns(&self, caller: Entity, entity: Entity) -> bool {
215 self.check_owns(caller, entity).is_ok()
216 }
217
218 /// Why a scope of `caller` may not despawn or relink `entity`.
219 ///
220 /// The same rule as [`World::owns`], answered with the reason instead of
221 /// one bit: an entity outside the subtree is another scope's to change, and
222 /// one in the shared subtree is the root's alone.
223 fn check_owns(&self, caller: Entity, entity: Entity) -> Result<(), EntityAccessError> {
224 if caller == self.root {
225 return Ok(());
226 }
227 if self.is_shared(entity) {
228 return Err(EntityAccessError::NotMovable {
229 entity,
230 scope: caller,
231 });
232 }
233 if entity != caller && !self.is_descendant(caller, entity) {
234 return Err(EntityAccessError::NotOwned {
235 entity,
236 scope: caller,
237 });
238 }
239 Ok(())
240 }
241
242 /// The parent of a live entity.
243 pub fn parent_scope(&self, entity: Entity) -> Result<Entity, EntityAccessError> {
244 self.tree.parent(entity)
245 }
246
247 /// The direct children of `entity`.
248 ///
249 /// Answers [`EntityAccessError::NotAlive`] for a handle that names no live
250 /// entity, which an empty list would otherwise hide.
251 pub fn children(&self, entity: Entity) -> Result<Vec<Entity>, EntityAccessError> {
252 self.location(entity)?;
253 Ok(self.tree.children(entity).to_vec())
254 }
255
256 /// The first row of `archetype` that holds content rather than scaffolding.
257 ///
258 /// This is where a query starts scanning an archetype, and what a count
259 /// leaves out. It is a row boundary rather than a per-row test so that
260 /// walking a row costs no identity check: the two roots share their
261 /// archetype with every entity spawned bare, which would otherwise need one
262 /// comparison per row.
263 #[inline]
264 #[must_use]
265 pub(crate) fn content_start(&self, archetype: u32) -> usize {
266 if archetype == self.scaffolding {
267 Self::SCAFFOLDING_ROWS
268 } else {
269 0
270 }
271 }
272
273 // -- scopes -------------------------------------------------------------
274
275 /// The scope of the root: everything in the world.
276 #[must_use]
277 pub fn root_scope(&self) -> Scope<'_> {
278 Scope::new(self, self.root)
279 }
280
281 /// The scope of `scope`.
282 pub fn scope(&self, scope: Entity) -> Result<Scope<'_>, EntityAccessError> {
283 self.tree.parent(scope)?;
284 Ok(Scope::new(self, scope))
285 }
286
287 /// The mutable scope of the root: everything in the world.
288 #[must_use]
289 pub fn root_scope_mut(&mut self) -> ScopeMut<'_> {
290 ScopeMut::new(self, self.root)
291 }
292
293 /// The mutable scope of `scope`.
294 pub fn scope_mut(&mut self, scope: Entity) -> Result<ScopeMut<'_>, EntityAccessError> {
295 self.tree.parent(scope)?;
296 Ok(ScopeMut::new(self, scope))
297 }
298
299 // -- handles -----------------------------------------------------------
300
301 /// A handle to an entity that does not exist yet, named `name`.
302 ///
303 /// The handle becomes live when a bundle is put on it, either with a
304 /// scope's spawn or by applying a queued [`crate::Commands::spawn`].
305 /// Reserving is where the caller says what the entity is, so the bundle
306 /// put on it later does not rename it.
307 pub fn reserve_entity(&self, name: &'static str) -> Entity {
308 self.entities_write().reserve(name)
309 }
310
311 /// Release a handle from [`World::reserve_entity`] that will never be
312 /// spawned.
313 ///
314 /// A reserved handle that is dropped without ever being spawned keeps its
315 /// index out of the pool; releasing it puts the index back, so a later
316 /// spawn reuses it. Returns whether `entity` was such a handle.
317 pub fn release_entity(&mut self, entity: Entity) -> bool {
318 if !self.entities_read().is_reserved(entity) {
319 return false;
320 }
321 self.entities_write().free(entity)
322 }
323
324 // -- structural changes ------------------------------------------------
325
326 /// Spawn `bundle` in `scope`.
327 ///
328 /// The entity is named after the bundle: a type of the caller's own names it
329 /// after itself, and a `bundle!` names it after the source position that
330 /// wrote the bundle. A dynamic bundle made by hand carries no name, so an
331 /// entity spawned from one has none.
332 pub(crate) fn spawn_in<B: Bundle>(&mut self, scope: Entity, bundle: B) -> Entity {
333 let name = bundle.name();
334 self.spawn_bundle_in(scope, name, bundle.into_bundle())
335 }
336
337 /// Spawn a bundle under `name`, whatever name the bundle carries.
338 pub(crate) fn spawn_named_in<B: Bundle>(
339 &mut self,
340 scope: Entity,
341 name: &'static str,
342 bundle: B,
343 ) -> Entity {
344 self.spawn_bundle_in(scope, name, bundle.into_bundle())
345 }
346
347 fn spawn_bundle_in(
348 &mut self,
349 scope: Entity,
350 name: &'static str,
351 bundle: DynamicBundle,
352 ) -> Entity {
353 let entity = self.entities_write().alloc(name);
354 self.insert_row(entity, scope, bundle);
355 self.finish_spawn(entity);
356 entity
357 }
358
359 /// Spawn `bundle` on `entity`, a handle from [`World::reserve_entity`], in
360 /// `scope`.
361 ///
362 /// Answers [`EntityAccessError::NotReserved`] when the handle is not a live
363 /// reservation from [`World::reserve_entity`]: spawning on a stale or
364 /// never-reserved handle would leave a row nobody can reach or free.
365 pub(crate) fn spawn_at_in<B: Bundle>(
366 &mut self,
367 entity: Entity,
368 scope: Entity,
369 bundle: B,
370 ) -> Result<(), EntityAccessError> {
371 if !self.entities_write().take_reserved(entity) {
372 return Err(EntityAccessError::NotReserved { entity });
373 }
374 // The handle was named when it was reserved, which is where the caller
375 // said what the entity is; the bundle does not rename it.
376 self.insert_row(entity, scope, bundle);
377 self.finish_spawn(entity);
378 Ok(())
379 }
380
381 /// Despawn `entity` and its whole subtree, on behalf of `caller`.
382 ///
383 /// Children are removed before the parent they lived in, so a child's
384 /// despawn callback still sees living ancestors. The answer is how many
385 /// entities the despawn took with it: the subtree is the scope's to know
386 /// about, and a caller that counts what it removed can say so.
387 pub(crate) fn despawn_in(
388 &mut self,
389 entity: Entity,
390 caller: Entity,
391 ) -> Result<usize, EntityAccessError> {
392 if self.is_scaffolding(entity) {
393 return Err(EntityAccessError::Scaffolding { entity });
394 }
395 self.location(entity)?;
396 self.check_owns(caller, entity)?;
397 let doomed = self.tree.subtree_post_order(entity);
398 for victim in &doomed {
399 self.remove_entity(*victim);
400 }
401 Ok(doomed.len())
402 }
403
404 /// Make `child` a child of `parent` on behalf of `caller`.
405 ///
406 /// Neither end may be a root or the shared scope itself, both must be
407 /// alive, and `parent` may not be inside `child`'s subtree: moving a scope
408 /// into its own descendant would cut the tree in two. The shared subtree is
409 /// readable from everywhere but it is the root's to rearrange, so only a
410 /// root caller may move an entity into or out of it.
411 pub(crate) fn link_in(
412 &mut self,
413 child: Entity,
414 parent: Entity,
415 caller: Entity,
416 ) -> Result<(), EntityAccessError> {
417 if self.is_scaffolding(child) {
418 return Err(EntityAccessError::Scaffolding { entity: child });
419 }
420 if self.is_scaffolding(parent) {
421 return Err(EntityAccessError::Scaffolding { entity: parent });
422 }
423 self.location(child)?;
424 self.location(parent)?;
425 self.check_owns(caller, child)?;
426 self.check_owns(caller, parent)?;
427 if child == parent || self.is_descendant(child, parent) {
428 return Err(EntityAccessError::WouldCycle { child, parent });
429 }
430 self.write_scope(child, parent);
431 Ok(())
432 }
433
434 /// Detach `child` from its parent and put it in `scope`, on behalf of
435 /// `caller`.
436 ///
437 /// `child` may not be the scope itself: that would make it its own parent,
438 /// which is how the tree says "this is a root". Scaffolding does not move,
439 /// and only a root caller may take an entity out of the shared subtree.
440 pub(crate) fn unlink_in(
441 &mut self,
442 child: Entity,
443 scope: Entity,
444 caller: Entity,
445 ) -> Result<(), EntityAccessError> {
446 if self.is_scaffolding(child) {
447 return Err(EntityAccessError::Scaffolding { entity: child });
448 }
449 if child == scope {
450 // Its own parent is how the tree says "this is a root".
451 return Err(EntityAccessError::WouldCycle {
452 child,
453 parent: scope,
454 });
455 }
456 self.location(child)?;
457 self.location(scope)?;
458 self.check_owns(caller, child)?;
459 if self.parent_scope(child)? == scope {
460 return Ok(());
461 }
462 self.write_scope(child, scope);
463 Ok(())
464 }
465
466 /// Move a live entity into `scope` and reindex it.
467 fn write_scope(&mut self, entity: Entity, scope: Entity) {
468 let location = self
469 .location(entity)
470 .unwrap_or_else(|_| panic!("{entity:?} has no row to move"));
471 let old = self
472 .tree
473 .parent(entity)
474 .unwrap_or_else(|_| panic!("{entity:?} is alive but not in the tree"));
475 if old == scope {
476 return;
477 }
478 self.archetypes
479 .get_mut(location.archetype())
480 .expect("a live entity's location names a registered archetype")
481 .move_scope(location.row(), old, scope);
482 self.tree_mut().attach(entity, scope);
483 }
484
485 // -- the row itself ----------------------------------------------------
486
487 /// Insert a row for `entity` in `scope`, made of the components `bundle`
488 /// carries.
489 fn insert_row<B: Bundle>(&mut self, entity: Entity, scope: Entity, bundle: B) {
490 let components = bundle.into_bundle().finish();
491 for component in &components {
492 self.ctors
493 .entry(component.type_id)
494 .or_insert(component.column);
495 self.names
496 .entry(component.type_id)
497 .or_insert(component.name);
498 }
499
500 let archetype = self.archetype_for_components(&components);
501 let target = self
502 .archetypes
503 .get_mut(archetype)
504 .expect("the archetype was just found or registered");
505 for component in components {
506 target.push_erased(component.type_id, component.value);
507 }
508 target.push_entity(entity, scope);
509 let row = (target.len() - 1) as u32;
510 self.entities_write()
511 .set_location(entity, Location { archetype, row });
512 self.tree_mut().attach(entity, scope);
513 }
514
515 /// Run the despawn callbacks of `entity` and drop its row and handle.
516 fn remove_entity(&mut self, entity: Entity) {
517 let Ok(location) = self.location(entity) else {
518 return;
519 };
520 self.run_lifecycle::<crate::OnDespawn>(entity);
521 self.tree_mut().detach(entity);
522 self.remove_row(location);
523 self.free_entity(entity);
524 }
525
526 /// Run the spawn callbacks of an entity whose row is already in place.
527 pub(crate) fn finish_spawn(&mut self, entity: Entity) {
528 self.run_lifecycle::<crate::OnSpawn>(entity);
529 }
530
531 /// Run the callback of the lifecycle component `C` the entity carries.
532 ///
533 /// The scope handed to it is the one the entity lives in, that of its
534 /// parent: a callback that wants the entity's own subtree descends into the
535 /// entity itself.
536 fn run_lifecycle<C: 'static + Lifecycle>(&mut self, entity: Entity) {
537 let Ok(scope) = self.parent_scope(entity) else {
538 return;
539 };
540 // The callback is moved out of the row for the run, so a callback that
541 // reaches for its own lifecycle component reads it instead of finding
542 // it held open by its own run.
543 let Some(callback) = self.take_lifecycle::<C>(entity) else {
544 return;
545 };
546 let scope = Scope::new(self, scope);
547 let mut callback = callback;
548 callback(&scope, entity);
549 self.restore_lifecycle::<C>(entity, callback);
550 }
551
552 /// Move the callback of the lifecycle component `C` out of the entity's row.
553 fn take_lifecycle<C: 'static + Lifecycle>(
554 &mut self,
555 entity: Entity,
556 ) -> Option<LifecycleCallback> {
557 let location = self.location(entity).ok()?;
558 let archetype = self.archetypes.get_mut(location.archetype()).ok()?;
559 let column = archetype.column_mut::<C>()?;
560 let cell = column.cells_mut().get_mut(location.row())?;
561 // SAFETY: `&mut World` excludes every query and every other reference to
562 // the world's components, so nothing else can be looking at this row.
563 Some(unsafe { &mut *cell.get() }.take())
564 }
565
566 /// Put back a callback moved out by the world's own run of it.
567 fn restore_lifecycle<C: 'static + Lifecycle>(
568 &mut self,
569 entity: Entity,
570 callback: LifecycleCallback,
571 ) {
572 let location = self
573 .location(entity)
574 .expect("a lifecycle callback was moved out of a live entity's row");
575 let archetype = self
576 .archetypes
577 .get_mut(location.archetype())
578 .expect("a live entity's location names a registered archetype");
579 let column = archetype
580 .column_mut::<C>()
581 .expect("the column the callback came from is still registered");
582 let cell = column
583 .cells_mut()
584 .get_mut(location.row())
585 .expect("the row still exists");
586 // SAFETY: as above, `&mut World` excludes every other reference.
587 unsafe { &mut *cell.get() }.restore(callback)
588 }
589
590 // -- queries and diagnostics -------------------------------------------
591
592 /// The name of a component type that has entered the world, as
593 /// [`core::any::type_name`] reported it, or `None` when no entity has ever
594 /// carried it.
595 #[must_use]
596 pub fn type_name(&self, type_id: TypeId) -> Option<&'static str> {
597 self.names.get(&type_id).copied()
598 }
599
600 // -- deferred structural changes ---------------------------------------
601
602 /// Apply every queued command, in order.
603 ///
604 /// Commands queued while applying are applied as well, after the ones
605 /// already in the queue. A command that fails does not stop the ones after
606 /// it: the queue is drained either way, and the caller is answered with the
607 /// first error.
608 pub fn apply(&mut self) -> Result<(), EntityAccessError> {
609 let mut first = Ok(());
610 loop {
611 let Some(command) = self.commands_write().pop_front() else {
612 return first;
613 };
614 let result = command.apply(self);
615 if first.is_ok() {
616 first = result;
617 }
618 }
619 }
620
621 // -- internals ---------------------------------------------------------
622
623 #[inline]
624 pub(crate) fn entities_read(&self) -> Ref<'_, Entities> {
625 self.entities
626 .try_borrow()
627 .unwrap_or_else(|_| panic!("the entity table is already exclusively borrowed"))
628 }
629
630 pub(crate) fn entities_write(&self) -> RefMut<'_, Entities> {
631 self.entities
632 .try_borrow_mut()
633 .unwrap_or_else(|_| panic!("the entity table is already borrowed"))
634 }
635
636 #[inline]
637 fn tree_mut(&mut self) -> &mut ScopeTree {
638 &mut self.tree
639 }
640
641 pub(crate) fn commands_write(&self) -> CommandsGuard<'_> {
642 self.commands
643 .try_borrow_mut()
644 .unwrap_or_else(|_| panic!("the command queue is already borrowed"))
645 }
646
647 /// Append a command to the deferred queue.
648 pub(crate) fn push_command(&self, command: Box<dyn Command>) {
649 self.commands_write().push_back(command);
650 }
651
652 /// Register a claim on one component type for one holder.
653 ///
654 /// Panics when a claim already held for the same type clashes with it. See
655 /// [`crate::borrow`] for what clashes.
656 #[track_caller]
657 pub(crate) fn claim(
658 &self,
659 group: u64,
660 type_id: TypeId,
661 name: &'static str,
662 mode: Mode,
663 rows: Rows,
664 origin: &'static core::panic::Location<'static>,
665 ) {
666 self.borrow_write()
667 .claim(group, type_id, name, mode, rows, origin);
668 }
669
670 /// The id the next holder files its claims under.
671 pub(crate) fn next_group(&self) -> u64 {
672 self.borrow_write().next_group()
673 }
674
675 /// Drop every claim one holder made.
676 pub(crate) fn release(&self, group: u64) {
677 self.borrow_write().release(group);
678 }
679
680 fn borrow_write(&self) -> RefMut<'_, BorrowLedger> {
681 self.borrow
682 .try_borrow_mut()
683 .unwrap_or_else(|_| panic!("the borrow ledger is already borrowed"))
684 }
685
686 /// The archetype with exactly the types of `components`, creating it when
687 /// it is new. Every type must have a registered column constructor.
688 ///
689 /// A hit allocates nothing: the types are hashed as the components are
690 /// walked and compared in place, so the type sequence is only materialised
691 /// when a new archetype has to be registered.
692 fn archetype_for_components(&mut self, components: &[BundleComponent]) -> u32 {
693 let found = self.archetypes.find_with(
694 components.iter().map(|component| component.type_id),
695 |stored| {
696 stored.len() == components.len()
697 && stored
698 .iter()
699 .zip(components)
700 .all(|(type_id, component)| *type_id == component.type_id)
701 },
702 );
703 if let Some(id) = found {
704 return id;
705 }
706 let types: Box<[TypeId]> = components
707 .iter()
708 .map(|component| component.type_id)
709 .collect();
710 let names: Box<[&'static str]> =
711 components.iter().map(|component| component.name).collect();
712 let columns: Box<[Box<dyn AnyColumn>]> = types
713 .iter()
714 .map(|type_id| {
715 let ctor = self.ctors.get(type_id).unwrap_or_else(|| {
716 panic!(
717 "no column constructor is registered for `{}`",
718 self.type_name(*type_id).unwrap_or("an unnamed type"),
719 )
720 });
721 ctor()
722 })
723 .collect();
724 self.archetypes
725 .register(Archetype::new(types, names, columns))
726 }
727
728 /// Where a live entity's components live.
729 #[inline]
730 pub(crate) fn location(&self, entity: Entity) -> Result<Location, EntityAccessError> {
731 self.entities_read().location(entity)
732 }
733
734 /// What a live entity is called, read from the row that stores it.
735 ///
736 /// This is the only durable copy of the label: the allocator keeps no name,
737 /// and a handle rebuilt from bare bits carries none.
738 pub fn entity_name(&self, entity: Entity) -> Result<&'static str, EntityAccessError> {
739 let location = self.location(entity)?;
740 Ok(self.archetypes.get(location.archetype())?.entities()[location.row()].name())
741 }
742
743 /// The archetypes, including the empty one.
744 ///
745 /// This is the storage itself, not a view of one scope: it holds every row
746 /// of every scope. Reading it through a [`Scope`] is what filters by
747 /// visibility.
748 #[must_use]
749 pub fn archetypes(&self) -> &Archetypes {
750 &self.archetypes
751 }
752
753 /// Drop the row at `location`, keeping every other location correct.
754 pub(crate) fn remove_row(&mut self, location: Location) {
755 let archetype = self
756 .archetypes
757 .get_mut(location.archetype())
758 .expect("a live entity's location names a registered archetype");
759 if let Some(moved) = archetype.swap_remove(location.row()) {
760 self.entities_write().set_location(
761 moved,
762 Location {
763 archetype: location.archetype(),
764 row: location.row() as u32,
765 },
766 );
767 }
768 }
769
770 pub(crate) fn free_entity(&mut self, entity: Entity) -> bool {
771 self.entities_write().free(entity)
772 }
773}
774
775impl core::fmt::Debug for World {
776 /// Reports the tree's roots and the archetype pool, not the entities.
777 ///
778 /// The entity table, the borrow ledger and the command queue live in cells,
779 /// and a debug print is most likely to run while one of them is already
780 /// borrowed. Borrowing them here would panic inside the panic message that
781 /// is being built, so they are left out rather than read on a best effort.
782 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
783 f.debug_struct("World")
784 .field("root", &self.root)
785 .field("shared", &self.shared)
786 .field("scaffolding", &self.scaffolding)
787 .field("archetypes", &self.archetypes)
788 .finish_non_exhaustive()
789 }
790}
791
792#[cfg(test)]
793mod tests {
794 use super::*;
795
796 #[derive(Clone, Copy, Debug)]
797 struct Marker;
798
799 /// The lookup behind the lifecycle hooks, which is its only caller: an
800 /// archetype that does not carry the component simply has no hook to run.
801 #[test]
802 fn a_component_the_archetype_does_not_carry_runs_no_hook() {
803 let mut world = World::new();
804 let entity = world.root_scope_mut().spawn(crate::bundle![Marker]);
805 assert!(
806 world
807 .take_lifecycle::<crate::lifecycle::OnSpawn>(entity)
808 .is_none(),
809 "the archetype has no OnSpawn column",
810 );
811 let dead = world.root_scope_mut().spawn(crate::bundle![Marker]);
812 world.root_scope_mut().despawn(dead).unwrap();
813 assert!(
814 world
815 .take_lifecycle::<crate::lifecycle::OnSpawn>(dead)
816 .is_none(),
817 "the handle is dead",
818 );
819 }
820}