Skip to main content

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}