Skip to main content

primase_core/
world.rs

1//! The world store: entities, typed components, opaque (unknown) components and world resources.
2//!
3//! Deliberately small and deterministic. Every column keeps its entities in ascending order, so iteration order is a
4//! function of the world's contents, never of hashing or insertion timing; writers that walk the world produce the
5//! same bytes for the same world.
6
7use std::any::{Any, TypeId};
8use std::collections::{BTreeMap, BTreeSet};
9use std::fmt;
10use std::sync::Arc;
11
12use crate::json::JsonError;
13
14/// An entity: a plain id. Ids are never reused within one world, so a stale id finds nothing rather than another
15/// entity's components.
16#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct Entity(u32);
18
19impl Entity {
20    /// The entity's index in creation order (serialisation uses it).
21    pub fn index(self) -> u32 {
22        self.0
23    }
24
25    /// The entity with this index. For readers of serialised worlds: an index the world never spawned finds nothing.
26    pub fn from_index(index: u32) -> Self {
27        Entity(index)
28    }
29}
30
31/// JSON (and any serde form) shows an entity as its index.
32impl serde::Serialize for Entity {
33    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
34        s.serialize_u32(self.0)
35    }
36}
37
38/// An index is meaningful only in the World it came from. Deserializing does not create
39/// an entity or relocate references: an importer must preserve or remap that identity
40/// before absorbing data into another World.
41impl<'de> serde::Deserialize<'de> for Entity {
42    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
43        <u32 as serde::Deserialize>::deserialize(d).map(Entity::from_index)
44    }
45}
46
47#[cfg(test)]
48mod entity_json_tests {
49    use super::Entity;
50
51    #[test]
52    fn entity_index_roundtrips_without_accepting_other_json_shapes() {
53        for index in [0, u32::MAX] {
54            let entity = Entity::from_index(index);
55            let value = serde_json::to_value(entity).unwrap();
56            assert_eq!(value, serde_json::json!(index));
57            assert_eq!(serde_json::from_value::<Entity>(value).unwrap(), entity);
58        }
59        for value in [
60            serde_json::json!(-1),
61            serde_json::json!(4294967296u64),
62            serde_json::json!(1.5),
63            serde_json::json!("1"),
64            serde_json::Value::Null,
65        ] {
66            assert!(serde_json::from_value::<Entity>(value).is_err());
67        }
68    }
69}
70
71impl fmt::Debug for Entity {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        write!(f, "e{}", self.0)
74    }
75}
76
77/// A name the world cannot give to what is being inserted: it already belongs to something of another kind.
78#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
79#[error(
80    "{name} is {held}: a name is a typed component's, an opaque component's or a resource's, one kind of them"
81)]
82pub struct NameClash {
83    pub name: String,
84    /// What holds it (`a typed component's name`).
85    pub held: &'static str,
86}
87
88/// An entity id a world cannot take.
89#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
90pub enum IdError {
91    #[error("entity {0:?} is not above every id already used")]
92    NotAscending(Entity),
93    #[error("entity {0:?} is the last id: the world cannot number another")]
94    Exhausted(Entity),
95    #[error("entity {0:?} is alive in this world already")]
96    Alive(Entity),
97}
98
99/// A typed component. `NAME` is namespaced and stable (`core.transform`, a destination's `material`, a source's
100/// `layered_material`): serialisation, pass declarations and reports use it, so renaming one is a format change.
101pub trait Component: Any + Clone + fmt::Debug + Send + Sync {
102    const NAME: &'static str;
103    /// Schema version of the component's content. Bump it when the meaning or layout of a field changes.
104    const VERSION: u32 = 1;
105    /// What the value holds of its entity's mesh primitives and vertices ([`Geometry`]). Stated by every component,
106    /// with no default, so data that describes a mesh can't be left behind by an edit of it unawares: the World's edit
107    /// paths take it from there.
108    const GEOMETRY: Geometry;
109
110    /// The component as JSON, for glTF extras, the debug text form and golden tests; `Ok(None)` for components
111    /// that are not shown (bulk data, handles). The view must never lose a value: components that can be shown
112    /// derive `serde::Serialize` and return `crate::json::to_value(self).map(Some)`, which refuses non-finite
113    /// floats instead of writing them as `null`.
114    fn to_json(&self) -> Result<Option<serde_json::Value>, JsonError> {
115        Ok(None)
116    }
117
118    /// The component's own invariants on entity `e` (indices in range, stream lengths equal, ...). The pass manager
119    /// runs it on every component after the reader, after every pass and before the writer, together with the
120    /// world's own check that every entity of [`Component::references`] is alive. World-wide rules (one name -> one
121    /// payload) are `pass::Validator`s instead.
122    fn verify(&self, _e: Entity, _w: &World) -> Result<(), String> {
123        Ok(())
124    }
125
126    /// The entities this component refers to (a prototype, materials, textures), appended to `out`: the edges
127    /// [`World::closure`] follows. A component holding entity references must declare every one of them.
128    fn references(&self, _out: &mut Vec<Entity>) {}
129
130    /// The bytes of bulk payload the value holds (vertex streams and indices, texture levels, triangle soups), for
131    /// memory reports: element counts times element sizes, not allocated capacity. 0 for small components.
132    fn payload_bytes(&self) -> u64 {
133        0
134    }
135
136    /// The component after its entity's mesh primitives were rebuilt, for a component that holds something per
137    /// primitive ([`Geometry::PerPrimitive`], [`Geometry::PerVertex`]): new primitive `i` comes from old primitive
138    /// `from[i]` (a source may repeat, when a primitive is split, or be absent, when one is dropped). Such a component
139    /// always answers (a value holding nothing per primitive answers with itself); `None`, the default, is for
140    /// components of [`Geometry::None`], and [`World::remap_primitives`] refuses a dependent component that gives it.
141    /// An index the component does not have is an error. [`remap_list`] does the work for a list with one entry per
142    /// primitive.
143    fn remap_primitives(&self, _from: &[usize]) -> Option<Result<Self, String>> {
144        None
145    }
146
147    /// The component after the vertices of its entity's mesh primitive `primitive` were compacted or reordered, for a
148    /// component that holds something per vertex ([`Geometry::PerVertex`]): new vertex `i` of that primitive is old
149    /// vertex `from[i]` (a source may repeat or be absent). Such a component always answers (with itself when it holds
150    /// nothing for that primitive); `None`, the default, is for the others, and [`World::remap_vertices`] refuses a
151    /// per-vertex component that gives it. An index the component does not have is an error. Every pass that compacts
152    /// or reorders a primitive's vertices calls [`World::remap_vertices`]. After a rebuild of the primitive list
153    /// ([`World::rebuild_primitives`], [`Component::remap_primitives`]) a primitive's per-vertex data is its source
154    /// primitive's, and the vertex map is relative to that source.
155    fn remap_vertices(&self, _primitive: usize, _from: &[u32]) -> Option<Result<Self, String>> {
156        None
157    }
158
159    /// The component after the vertices of its entity's mesh primitive `primitive` were rebuilt as blends of old ones
160    /// ([`VertexBlend`]), for a component that holds something per vertex ([`Geometry::PerVertex`]): new vertex `i`
161    /// is the combination `from[i]` of old vertices, in whatever way the component's data combines (a morph target's
162    /// delta is interpolated, the way the surface it moves is). It answers as [`Component::remap_vertices`] does: with
163    /// itself when it holds nothing for that primitive; `None`, the default, is for a component that does not know how
164    /// to combine its data, and [`World::blend_vertices`] refuses a per-vertex component that gives it. An index the
165    /// component does not have is an error. A vertex that is a copy of one old vertex ([`VertexBlend::copy`]) is the
166    /// case [`Component::remap_vertices`] states, and a component answering one answers the other alike.
167    fn blend_vertices(&self, _primitive: usize, _from: &[VertexBlend]) -> Option<Result<Self, String>> {
168        None
169    }
170
171    /// The component after its entity's local space was mapped by `l` (a pass that bakes a placement's mirror or
172    /// shear into a copy of its geometry, so transforms stay rigid). [`World::apply_linear`] calls it for every
173    /// component of the entity. The default is [`Linearity::Unsupported`]: a component that holds local-space
174    /// geometry and does not say how it follows is never silently left behind; one without geometry says
175    /// [`Linearity::Invariant`].
176    fn apply_linear(&self, _l: &crate::Linear) -> Linearity<Self> {
177        Linearity::Unsupported
178    }
179
180    /// The component after `resolve-state` ([`crate::state::ResolveState`]) gave the axes in `resolved` their values: a
181    /// component that holds [`crate::state::Clause`]s of its own (a record of parts each present in some states) reduces
182    /// them as `core.condition` is reduced ([`crate::state::Resolved::reduce`]: a clause that fails is dropped, a clause
183    /// left with no literal holds whatever the other axes are). [`Restated::Absent`] says the entity is not present in
184    /// this state (every clause failed): it is despawned as one whose `core.condition` fails is. The default holds no
185    /// clause: [`Restated::Unchanged`].
186    fn restate(&self, _resolved: &crate::state::Resolved<'_>) -> Restated<Self> {
187        Restated::Unchanged
188    }
189}
190
191/// What a component becomes when `resolve-state` resolves axes ([`Component::restate`]).
192#[derive(Clone, Debug, PartialEq)]
193pub enum Restated<T> {
194    /// It names no resolved axis: kept as it is.
195    Unchanged,
196    /// Its clauses reduced.
197    Replaced(T),
198    /// Nothing of it is present in the resolved state: its entity is not.
199    Absent,
200}
201
202/// What a component's value holds of its entity's mesh ([`Component::GEOMETRY`]): whether an edit of the primitives
203/// or vertices must carry it along. A component holding geometry of its own (`core.mesh`, `core.mesh_file`, a source
204/// model a reader keeps beside it) describes no other component's primitives: [`Geometry::None`].
205#[derive(Clone, Copy, Debug, PartialEq, Eq)]
206pub enum Geometry {
207    /// Nothing per primitive or vertex of its entity's mesh: kept as it is whatever an edit does to them.
208    None,
209    /// Something per primitive of its entity's mesh (a material per primitive, provenance per part): it implements
210    /// [`Component::remap_primitives`], goes with the mesh ([`World::remove_mesh`]), and an edit that rebuilds the
211    /// primitives refuses it when it does not answer.
212    PerPrimitive,
213    /// Something per vertex of its entity's mesh primitives (and so per primitive): as [`Geometry::PerPrimitive`], and
214    /// it implements [`Component::remap_vertices`] too.
215    PerVertex,
216}
217
218impl Geometry {
219    /// Whether the value describes its entity's mesh, so it goes when the mesh does.
220    pub fn describes_mesh(self) -> bool {
221        self != Geometry::None
222    }
223}
224
225/// What a component becomes when its entity's local space is mapped by a [`crate::Linear`]
226/// ([`Component::apply_linear`]).
227#[derive(Clone, Debug, PartialEq)]
228pub enum Linearity<T> {
229    /// It holds no local-space geometry: kept as it is.
230    Invariant,
231    /// It holds geometry, mapped.
232    Applied(T),
233    /// What it says is no longer true of the mapped geometry (a file the geometry was read from): removed.
234    Drop,
235    /// It cannot follow: the entity is left as it was.
236    Unsupported,
237}
238
239/// `list` (one entry per primitive) for primitives rebuilt from `from` ([`Component::remap_primitives`]).
240pub fn remap_list<T: Clone>(list: &[T], from: &[usize]) -> Result<Vec<T>, String> {
241    from.iter()
242        .map(|&i| {
243            list.get(i)
244                .cloned()
245                .ok_or_else(|| format!("primitive {i} of {}", list.len()))
246        })
247        .collect()
248}
249
250/// A new vertex of a triangle primitive made as a weighted combination of up to three old vertices of it (the corners
251/// of the triangle it lies in): `sum weights[k] * old vertex sources[k]`, the weights non-negative and summing to 1. A
252/// copy of one old vertex has weight 1 on it; unused entries have weight 0. See [`Component::blend_vertices`].
253#[derive(Clone, Copy, Debug, PartialEq)]
254pub struct VertexBlend {
255    pub sources: [u32; 3],
256    pub weights: [f32; 3],
257}
258
259impl VertexBlend {
260    /// The old vertex `v` itself.
261    pub fn copy(v: u32) -> VertexBlend {
262        VertexBlend {
263            sources: [v; 3],
264            weights: [1.0, 0.0, 0.0],
265        }
266    }
267
268    /// The old vertices with a weight above zero, with their weights, in order.
269    pub fn terms(&self) -> impl Iterator<Item = (u32, f32)> + '_ {
270        self.sources
271            .iter()
272            .copied()
273            .zip(self.weights)
274            .filter(|&(_, w)| w > 0.0)
275    }
276}
277
278/// A component's value rebuilt for blended vertices, not stored yet, with the column's type.
279type Blended = (TypeId, Box<dyn Any + Send>);
280
281/// A world resource: one value per world (the frame, a game's archive index, a run's options, the environment).
282pub trait Resource: Any + Clone + fmt::Debug + Send + Sync {
283    const NAME: &'static str;
284    const VERSION: u32 = 1;
285
286    /// As [`Component::to_json`].
287    fn to_json(&self) -> Result<Option<serde_json::Value>, JsonError> {
288        Ok(None)
289    }
290
291    /// The resource's own invariants in `w`; as [`Component::verify`], run by the pass manager's verifier.
292    fn verify(&self, _w: &World) -> Result<(), String> {
293        Ok(())
294    }
295
296    /// The entities this resource refers to, appended to `out`. A resource holding entity references must declare
297    /// every one of them and implement [`Resource::retain_references`].
298    fn references(&self, _out: &mut Vec<Entity>) {}
299
300    /// Forget every reference to an entity `keep` refuses (set it to "none"). The world calls it whenever entities
301    /// leave it ([`World::despawn`], [`World::retain`], [`World::move_components`]) and on the copy a
302    /// [`World::subset`] or [`World::split_off`] part gets, so a resource never refers to an entity its world lacks.
303    fn retain_references(&mut self, _keep: &dyn Fn(Entity) -> bool) {}
304}
305
306/// One component (or resource) as JSON, with the schema version it is written with.
307#[derive(Clone, Debug, PartialEq)]
308pub struct ComponentJson<'w> {
309    pub name: &'w str,
310    pub version: u32,
311    /// `None`: no JSON view (opaque bytes, typed components that are not shown).
312    pub value: Option<serde_json::Value>,
313}
314
315/// A component whose JSON view would lose a value.
316#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
317#[error("{component}{}: {message}", entity.map(|e| format!(" on {e:?}")).unwrap_or_default())]
318pub struct ComponentJsonError {
319    pub component: String,
320    /// `None` for a resource.
321    pub entity: Option<Entity>,
322    pub message: String,
323}
324
325/// The content of a component this build does not know: carried through reading and writing untouched.
326#[derive(Clone, Debug, PartialEq)]
327pub enum OpaqueData {
328    Json(serde_json::Value),
329    Bytes(Vec<u8>),
330}
331
332/// An opaque component value with the schema version it was written with.
333#[derive(Clone, Debug, PartialEq)]
334pub struct Opaque {
335    pub version: u32,
336    pub data: OpaqueData,
337}
338
339/// The storage of one component type: entity -> value, ordered by entity. Each value is a shared handle: a clone of the
340/// column (of the world) shares every value with it, and writing a value that is shared copies it first, so neither side
341/// sees the other's writes ([`Column::get_shared`]).
342#[derive(Clone, Debug)]
343pub struct Column<T> {
344    values: BTreeMap<Entity, Arc<T>>,
345}
346
347impl<T> Default for Column<T> {
348    fn default() -> Self {
349        Column {
350            values: BTreeMap::new(),
351        }
352    }
353}
354
355impl<T> Column<T> {
356    pub fn get(&self, e: Entity) -> Option<&T> {
357        self.values.get(&e).map(Arc::as_ref)
358    }
359
360    /// `e`'s value as a shared handle: the column's own, not a copy. A later write through the column copies the value
361    /// first, so the handle keeps what it was given.
362    pub fn get_shared(&self, e: Entity) -> Option<Arc<T>> {
363        self.values.get(&e).cloned()
364    }
365
366    pub fn contains(&self, e: Entity) -> bool {
367        self.values.contains_key(&e)
368    }
369
370    pub fn len(&self) -> usize {
371        self.values.len()
372    }
373
374    pub fn is_empty(&self) -> bool {
375        self.values.is_empty()
376    }
377
378    /// Entities and values in ascending entity order.
379    pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Entity, &T)> + ExactSizeIterator {
380        self.values.iter().map(|(e, v)| (*e, v.as_ref()))
381    }
382
383    pub fn entities(&self) -> impl DoubleEndedIterator<Item = Entity> + ExactSizeIterator + '_ {
384        self.values.keys().copied()
385    }
386
387    /// `e`'s value taken out as the shared handle: the column's own, never a copy, whoever else shares it.
388    fn remove_shared(&mut self, e: Entity) -> Option<Arc<T>> {
389        self.values.remove(&e)
390    }
391}
392
393impl<T: Clone> Column<T> {
394    /// `e`'s value to write: a value another clone of the column still shares is copied first.
395    pub fn get_mut(&mut self, e: Entity) -> Option<&mut T> {
396        self.values.get_mut(&e).map(Arc::make_mut)
397    }
398
399    /// Every value to write, in ascending entity order: each one still shared is copied first.
400    pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = (Entity, &mut T)> + ExactSizeIterator {
401        self.values.iter_mut().map(|(e, v)| (*e, Arc::make_mut(v)))
402    }
403
404    fn insert(&mut self, e: Entity, value: T) -> Option<T> {
405        self.values.insert(e, Arc::new(value)).map(Arc::unwrap_or_clone)
406    }
407
408    /// The value taken out: the column's own where nothing else shares it, else a copy.
409    fn remove(&mut self, e: Entity) -> Option<T> {
410        self.remove_shared(e).map(Arc::unwrap_or_clone)
411    }
412}
413
414/// Type-erased operations the world needs on every column.
415trait AnyColumn: Any + Send + Sync {
416    fn name(&self) -> &'static str;
417    fn len(&self) -> usize;
418    fn contains(&self, e: Entity) -> bool;
419    fn remove_entity(&mut self, e: Entity);
420    fn version(&self) -> u32;
421    fn geometry(&self) -> Geometry;
422    /// `None` when the entity has no such component; else its JSON view.
423    fn json(&self, e: Entity) -> Option<Result<Option<serde_json::Value>, JsonError>>;
424    /// Every value's `Component::verify`, and that each entity its `Component::references` names is alive, as
425    /// (entity, message) for those that fail, in entity order.
426    fn verify(&self, w: &World) -> Vec<(Entity, String)>;
427    /// Every value through `Debug`, in entity order.
428    fn visit_debug(&self, f: &mut dyn FnMut(Entity, &dyn fmt::Debug));
429    fn entities(&self) -> Vec<Entity>;
430    /// [`Component::references`] of entity `e`'s value, if it has one.
431    fn references(&self, e: Entity, out: &mut Vec<Entity>);
432    /// The sum of every value's [`Component::payload_bytes`].
433    fn payload_bytes(&self) -> u64;
434    fn clone_box(&self) -> Box<dyn AnyColumn>;
435    /// A copy holding only the values of `keep`.
436    fn subset_box(&self, keep: &BTreeSet<Entity>) -> Box<dyn AnyColumn>;
437    /// Drop the values of entities outside `keep`.
438    fn retain(&mut self, keep: &BTreeSet<Entity>);
439    /// Move the values of `keep` out into a column of their own.
440    fn split_off_box(&mut self, keep: &BTreeSet<Entity>) -> Box<dyn AnyColumn>;
441    /// Move every value of `other`, a column of the same type, in.
442    fn absorb(&mut self, other: Box<dyn AnyColumn>);
443    /// Move `from`'s value, if it has one, onto `to` (replacing `to`'s).
444    fn move_entity(&mut self, from: Entity, to: Entity);
445    /// `e`'s value remapped to rebuilt primitives ([`Component::remap_primitives`]), not stored yet; `None` when `e`
446    /// has none or it does not follow primitives.
447    fn remapped(&self, e: Entity, from: &[usize]) -> Option<Result<Box<dyn Any + Send>, String>>;
448    /// `e`'s value with primitive `primitive`'s vertices remapped ([`Component::remap_vertices`]), not stored yet;
449    /// `None` when `e` has none or it holds nothing per vertex of that primitive.
450    fn vertices_remapped(
451        &self,
452        e: Entity,
453        primitive: usize,
454        from: &[u32],
455    ) -> Option<Result<Box<dyn Any + Send>, String>>;
456    /// `e`'s value with primitive `primitive`'s vertices rebuilt as blends ([`Component::blend_vertices`]), not stored
457    /// yet; `None` when `e` has none or it cannot combine its vertices.
458    fn vertices_blended(
459        &self,
460        e: Entity,
461        primitive: usize,
462        from: &[VertexBlend],
463    ) -> Option<Result<Box<dyn Any + Send>, String>>;
464    /// Store a value [`AnyColumn::remapped`], [`AnyColumn::vertices_remapped`], [`AnyColumn::vertices_blended`] or
465    /// [`AnyColumn::linear`] made.
466    fn put_remapped(&mut self, e: Entity, value: Box<dyn Any + Send>);
467    /// A copy of `from`'s value, if it has one, onto `to`.
468    fn copy_entity(&mut self, from: Entity, to: Entity);
469    /// `e`'s value under [`Component::apply_linear`], not stored yet; `None` when `e` has none.
470    fn linear(&self, e: Entity, l: &crate::Linear) -> Option<Linearity<Box<dyn Any + Send>>>;
471    /// Every value restated ([`Component::restate`]) in place; the entities whose value says they are not present.
472    fn restate_all(&mut self, resolved: &crate::state::Resolved<'_>) -> Vec<Entity>;
473    fn as_any(&self) -> &dyn Any;
474    fn as_any_mut(&mut self) -> &mut dyn Any;
475}
476
477impl<T: Component> AnyColumn for Column<T> {
478    fn name(&self) -> &'static str {
479        T::NAME
480    }
481    fn len(&self) -> usize {
482        self.values.len()
483    }
484    fn contains(&self, e: Entity) -> bool {
485        self.values.contains_key(&e)
486    }
487    fn remove_entity(&mut self, e: Entity) {
488        self.values.remove(&e);
489    }
490    fn version(&self) -> u32 {
491        T::VERSION
492    }
493    fn geometry(&self) -> Geometry {
494        T::GEOMETRY
495    }
496    fn json(&self, e: Entity) -> Option<Result<Option<serde_json::Value>, JsonError>> {
497        self.values.get(&e).map(|v| v.to_json())
498    }
499    fn verify(&self, w: &World) -> Vec<(Entity, String)> {
500        let mut out = Vec::new();
501        let mut refs = Vec::new();
502        for (e, v) in &self.values {
503            if let Err(m) = v.verify(*e, w) {
504                out.push((*e, m));
505            }
506            refs.clear();
507            v.references(&mut refs);
508            if let Some(r) = refs.iter().find(|r| !w.alive.contains(r)) {
509                out.push((*e, format!("refers to {r:?}, which is not alive")));
510            }
511        }
512        out
513    }
514    fn visit_debug(&self, f: &mut dyn FnMut(Entity, &dyn fmt::Debug)) {
515        for (e, v) in &self.values {
516            f(*e, v);
517        }
518    }
519    fn entities(&self) -> Vec<Entity> {
520        self.values.keys().copied().collect()
521    }
522    fn references(&self, e: Entity, out: &mut Vec<Entity>) {
523        if let Some(v) = self.values.get(&e) {
524            v.references(out);
525        }
526    }
527    fn payload_bytes(&self) -> u64 {
528        self.values.values().map(|v| v.payload_bytes()).sum()
529    }
530    fn clone_box(&self) -> Box<dyn AnyColumn> {
531        Box::new(self.clone())
532    }
533    fn subset_box(&self, keep: &BTreeSet<Entity>) -> Box<dyn AnyColumn> {
534        Box::new(Column {
535            values: subset_of(&self.values, keep),
536        })
537    }
538    fn retain(&mut self, keep: &BTreeSet<Entity>) {
539        self.values.retain(|e, _| keep.contains(e));
540    }
541    fn split_off_box(&mut self, keep: &BTreeSet<Entity>) -> Box<dyn AnyColumn> {
542        Box::new(Column {
543            values: keep
544                .iter()
545                .filter_map(|e| self.values.remove(e).map(|v| (*e, v)))
546                .collect(),
547        })
548    }
549    fn absorb(&mut self, mut other: Box<dyn AnyColumn>) {
550        let other = other
551            .as_any_mut()
552            .downcast_mut::<Column<T>>()
553            .expect("absorbing a column of the same type");
554        self.values.append(&mut other.values);
555    }
556    fn move_entity(&mut self, from: Entity, to: Entity) {
557        if let Some(v) = self.values.remove(&from) {
558            self.values.insert(to, v);
559        }
560    }
561    fn remapped(&self, e: Entity, from: &[usize]) -> Option<Result<Box<dyn Any + Send>, String>> {
562        let r = self.values.get(&e)?.remap_primitives(from)?;
563        Some(r.map(|v| Box::new(v) as Box<dyn Any + Send>))
564    }
565    fn vertices_remapped(
566        &self,
567        e: Entity,
568        primitive: usize,
569        from: &[u32],
570    ) -> Option<Result<Box<dyn Any + Send>, String>> {
571        let r = self.values.get(&e)?.remap_vertices(primitive, from)?;
572        Some(r.map(|v| Box::new(v) as Box<dyn Any + Send>))
573    }
574    fn vertices_blended(
575        &self,
576        e: Entity,
577        primitive: usize,
578        from: &[VertexBlend],
579    ) -> Option<Result<Box<dyn Any + Send>, String>> {
580        let r = self.values.get(&e)?.blend_vertices(primitive, from)?;
581        Some(r.map(|v| Box::new(v) as Box<dyn Any + Send>))
582    }
583    fn put_remapped(&mut self, e: Entity, value: Box<dyn Any + Send>) {
584        let v = *(value as Box<dyn Any>)
585            .downcast::<T>()
586            .expect("a value remapped by this column");
587        self.values.insert(e, Arc::new(v));
588    }
589    fn copy_entity(&mut self, from: Entity, to: Entity) {
590        if let Some(v) = self.values.get(&from).cloned() {
591            self.values.insert(to, v);
592        }
593    }
594    fn linear(&self, e: Entity, l: &crate::Linear) -> Option<Linearity<Box<dyn Any + Send>>> {
595        Some(match self.values.get(&e)?.apply_linear(l) {
596            Linearity::Invariant => Linearity::Invariant,
597            Linearity::Applied(v) => Linearity::Applied(Box::new(v) as Box<dyn Any + Send>),
598            Linearity::Drop => Linearity::Drop,
599            Linearity::Unsupported => Linearity::Unsupported,
600        })
601    }
602    fn restate_all(&mut self, resolved: &crate::state::Resolved<'_>) -> Vec<Entity> {
603        let mut absent = Vec::new();
604        for (e, v) in &mut self.values {
605            match v.restate(resolved) {
606                Restated::Unchanged => {}
607                Restated::Replaced(restated) => *v = Arc::new(restated),
608                Restated::Absent => absent.push(*e),
609            }
610        }
611        absent
612    }
613    fn as_any(&self) -> &dyn Any {
614        self
615    }
616    fn as_any_mut(&mut self) -> &mut dyn Any {
617        self
618    }
619}
620
621/// The entries of `values` whose entity is in `keep`, walking the smaller of the two.
622fn subset_of<T: Clone>(values: &BTreeMap<Entity, T>, keep: &BTreeSet<Entity>) -> BTreeMap<Entity, T> {
623    if keep.len() < values.len() {
624        keep.iter()
625            .filter_map(|e| values.get(e).map(|v| (*e, v.clone())))
626            .collect()
627    } else {
628        values
629            .iter()
630            .filter(|(e, _)| keep.contains(e))
631            .map(|(e, v)| (*e, v.clone()))
632            .collect()
633    }
634}
635
636trait AnyResource: Any + Send + Sync {
637    fn name(&self) -> &'static str;
638    fn version(&self) -> u32;
639    fn json(&self) -> Result<Option<serde_json::Value>, JsonError>;
640    fn debug(&self) -> &dyn fmt::Debug;
641    fn verify(&self, w: &World) -> Result<(), String>;
642    fn references(&self, out: &mut Vec<Entity>);
643    /// Forget the references `keep` refuses; the first one still held afterwards, if any (the resource broke its
644    /// contract).
645    fn retain_references(&mut self, keep: &dyn Fn(Entity) -> bool) -> Option<Entity>;
646    fn clone_box(&self) -> Box<dyn AnyResource>;
647    fn as_any(&self) -> &dyn Any;
648    fn as_any_mut(&mut self) -> &mut dyn Any;
649}
650
651impl<T: Resource> AnyResource for T {
652    fn name(&self) -> &'static str {
653        T::NAME
654    }
655    fn version(&self) -> u32 {
656        T::VERSION
657    }
658    fn json(&self) -> Result<Option<serde_json::Value>, JsonError> {
659        self.to_json()
660    }
661    fn debug(&self) -> &dyn fmt::Debug {
662        self
663    }
664    fn verify(&self, w: &World) -> Result<(), String> {
665        Resource::verify(self, w)
666    }
667    fn references(&self, out: &mut Vec<Entity>) {
668        Resource::references(self, out);
669    }
670    fn retain_references(&mut self, keep: &dyn Fn(Entity) -> bool) -> Option<Entity> {
671        Resource::retain_references(self, keep);
672        let mut left = Vec::new();
673        Resource::references(self, &mut left);
674        left.into_iter().find(|&e| !keep(e))
675    }
676    fn clone_box(&self) -> Box<dyn AnyResource> {
677        Box::new(self.clone())
678    }
679    fn as_any(&self) -> &dyn Any {
680        self
681    }
682    fn as_any_mut(&mut self) -> &mut dyn Any {
683        self
684    }
685}
686
687/// Entities with their components, opaque components and resources.
688#[derive(Default)]
689pub struct World {
690    next: u32,
691    /// Alive entities. Despawned ids stay out forever.
692    alive: std::collections::BTreeSet<Entity>,
693    columns: BTreeMap<TypeId, Box<dyn AnyColumn>>,
694    /// Component name -> owning type, to refuse two Rust types claiming one name.
695    names: BTreeMap<&'static str, TypeId>,
696    opaque: BTreeMap<String, BTreeMap<Entity, Opaque>>,
697    resources: BTreeMap<TypeId, Box<dyn AnyResource>>,
698    opaque_resources: BTreeMap<String, Opaque>,
699    /// While a pass runs with conservation diagnostics on ([`crate::ledger`]): per entity whose primitives it rebuilt
700    /// ([`World::rebuild_primitives`]), the rebuilds composed; `None` for an entity whose mesh was also replaced another
701    /// way in between (counted net).
702    rebuilds: Option<RebuildLog>,
703    /// While a pass runs ([`World::start_effects`]): what it did that the pass manager can't see by comparing the world
704    /// before and after (resources written in place or replaced, entities filled by copying another).
705    effects: Option<Effects>,
706    /// What entities leaving dropped to keep the world whole ([`World::retain`], [`World::despawn`],
707    /// [`World::move_components`]), until [`World::take_dropped`]: the pass manager counts it in the log of the pass
708    /// that made it.
709    dropped: Dropped,
710}
711
712/// What a world dropped to stay whole when entities left it: the render graph's steps that drew with an entity that
713/// left ([`crate::render_graph::RenderGraph::retain_steps`]), and the step bindings and step draws that named the
714/// draws only those steps made ([`crate::StepBindings`], [`crate::StepDraws`]), which would name draws the graph no
715/// longer has.
716#[derive(Clone, Debug, Default, PartialEq, Eq)]
717pub struct Dropped {
718    pub graph: crate::render_graph::StepsDropped,
719    /// (material, draw), for each draw a material's step bindings named.
720    pub step_bindings: Vec<(Entity, String)>,
721    /// (placement, draw), for each draw a placement's step draws named.
722    pub step_draws: Vec<(Entity, String)>,
723}
724
725impl Dropped {
726    pub fn is_empty(&self) -> bool {
727        self.graph.is_empty() && self.step_bindings.is_empty() && self.step_draws.is_empty()
728    }
729
730    fn append(&mut self, mut other: Dropped) {
731        self.graph.steps.append(&mut other.graph.steps);
732        self.graph.lighting |= other.graph.lighting;
733        self.graph.picture |= other.graph.picture;
734        self.step_bindings.append(&mut other.step_bindings);
735        self.step_draws.append(&mut other.step_draws);
736    }
737}
738
739impl fmt::Display for Dropped {
740    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
741        let mut parts = Vec::new();
742        if !self.graph.steps.is_empty() {
743            let steps: Vec<String> = self
744                .graph
745                .steps
746                .iter()
747                .map(|(name, gone)| format!("{name} (drew with {gone:?})"))
748                .collect();
749            parts.push(format!("render graph steps {}", steps.join(", ")));
750        }
751        if self.graph.lighting {
752            parts.push("the render graph's lighting pipeline".to_owned());
753        }
754        if self.graph.picture {
755            parts.push("the render graph's picture".to_owned());
756        }
757        for (what, list) in [
758            ("step bindings", &self.step_bindings),
759            ("step draws", &self.step_draws),
760        ] {
761            if !list.is_empty() {
762                let named: Vec<String> = list.iter().map(|(e, draw)| format!("{e:?} {draw}")).collect();
763                parts.push(format!("{what} {}", named.join(", ")));
764            }
765        }
766        write!(f, "{}", parts.join("; "))
767    }
768}
769
770/// Entities taken from a world into one of their own ([`World::part`], [`World::split_part`]), and what that world
771/// dropped to stay whole.
772#[derive(Debug)]
773pub struct Part {
774    pub world: World,
775    pub dropped: Dropped,
776}
777
778/// What a pass did to a world that a before/after comparison of names doesn't show ([`World::start_effects`]).
779#[derive(Clone, Debug, Default)]
780pub(crate) struct Effects {
781    /// Resources it replaced or borrowed mutably (an existing one written, or written in place), by name.
782    pub(crate) resources_written: BTreeSet<String>,
783    /// Resources it took away ([`World::remove_resource`]), by name: one the world holds again afterwards was
784    /// replaced, a write as much as [`World::insert_resource`] over it.
785    pub(crate) resources_removed: BTreeSet<String>,
786    /// Copies it made: (source, target) for each [`World::duplicate`] and [`World::copy_components`]. An exemption,
787    /// not a check: a name a copy puts on its target is the source's, so it counts as no addition.
788    pub(crate) copies: Vec<(Entity, Entity)>,
789    /// What entities leaving made the world drop to stay whole ([`World::take_dropped`]): an exemption as copies are,
790    /// the step bindings and step draws it took counted in the pass's log, not declared by the pass.
791    pub(crate) dropped: Dropped,
792}
793
794/// The primitive rebuilds a pass made, per entity; `None` when its mesh was also replaced another way between two of
795/// them.
796pub(crate) type RebuildLog = BTreeMap<Entity, Option<Rebuilt>>;
797
798/// One mesh's rebuilds in a pass, composed.
799#[derive(Clone, Debug)]
800pub(crate) struct Rebuilt {
801    /// The mesh the first rebuild started from ([`crate::Mesh`]'s identity) and its primitive count.
802    pub(crate) source: u64,
803    pub(crate) first: usize,
804    /// For each primitive of the mesh the last rebuild made, the source primitive it comes from.
805    pub(crate) from: Vec<usize>,
806    /// The mesh the last rebuild made.
807    pub(crate) made: u64,
808}
809
810impl Clone for World {
811    fn clone(&self) -> Self {
812        World {
813            next: self.next,
814            alive: self.alive.clone(),
815            columns: self.columns.iter().map(|(k, v)| (*k, v.clone_box())).collect(),
816            names: self.names.clone(),
817            opaque: self.opaque.clone(),
818            resources: self.resources.iter().map(|(k, v)| (*k, v.clone_box())).collect(),
819            opaque_resources: self.opaque_resources.clone(),
820            rebuilds: None,
821            effects: None,
822            dropped: Dropped::default(),
823        }
824    }
825}
826
827impl fmt::Debug for World {
828    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
829        let mut counts: BTreeMap<&str, usize> = BTreeMap::new();
830        for c in self.columns.values() {
831            counts.insert(c.name(), c.len());
832        }
833        for (name, col) in &self.opaque {
834            counts.insert(name, col.len());
835        }
836        f.debug_struct("World")
837            .field("entities", &self.alive.len())
838            .field("components", &counts)
839            .finish()
840    }
841}
842
843impl World {
844    pub fn new() -> Self {
845        Self::default()
846    }
847
848    /// Every resource, copied, with its references to entities outside `alive` forgotten, and what the render graph
849    /// dropped doing so. A resource that keeps one breaks the contract of [`Resource::retain_references`]: a bug,
850    /// refused here (a part would refer to an entity it lacks), in release as in debug.
851    fn resources_for(
852        &self,
853        alive: &BTreeSet<Entity>,
854    ) -> (
855        BTreeMap<TypeId, Box<dyn AnyResource>>,
856        crate::render_graph::StepsDropped,
857    ) {
858        let mut graph = crate::render_graph::StepsDropped::default();
859        let resources = self
860            .resources
861            .iter()
862            .map(|(k, v)| {
863                let mut r = v.clone_box();
864                if let Some(g) = r.as_any_mut().downcast_mut::<crate::render_graph::RenderGraph>() {
865                    graph = g.retain_steps(&|e| alive.contains(&e));
866                }
867                if let Some(e) = r.retain_references(&|e| alive.contains(&e)) {
868                    panic!(
869                        "{} keeps a reference to {e:?}, which it was told to forget",
870                        r.name()
871                    );
872                }
873                (*k, r)
874            })
875            .collect();
876        (resources, graph)
877    }
878
879    /// The step bindings and step draws naming the draws of the render graph's steps that went, taken away
880    /// ([`crate::step_bindings::retain_made`]), with what the graph dropped: nothing where it dropped nothing.
881    fn reconcile(&mut self, graph: crate::render_graph::StepsDropped) -> Dropped {
882        if graph.is_empty() {
883            return Dropped::default();
884        }
885        Dropped {
886            graph,
887            ..crate::step_bindings::retain_made(self)
888        }
889    }
890
891    /// What entities leaving dropped since the last call ([`World::retain`], [`World::despawn`],
892    /// [`World::move_components`]); a [`World::part`] states its own.
893    pub fn take_dropped(&mut self) -> Dropped {
894        std::mem::take(&mut self.dropped)
895    }
896
897    /// Every resource forgets its references to the entities `gone` accepts. A whole selection leaving
898    /// (`strict`: [`World::retain`]) checks the contract of [`Resource::retain_references`] in release too; one
899    /// entity leaving ([`World::despawn`], [`World::move_components`]) only in debug builds, where checking each would
900    /// cost a pass over every resource's references per entity (the verifier names a dangling reference either way).
901    /// The render graph's steps that drew with one of them go, and the step bindings and step draws naming their draws
902    /// with them (on entities still alive), recorded until [`World::take_dropped`].
903    fn forget_in_resources(&mut self, gone: impl Fn(Entity) -> bool, strict: bool) {
904        let graph = self
905            .resources
906            .get_mut(&TypeId::of::<crate::render_graph::RenderGraph>())
907            .and_then(|r| r.as_any_mut().downcast_mut::<crate::render_graph::RenderGraph>())
908            .map(|g| g.retain_steps(&|e| !gone(e)))
909            .unwrap_or_default();
910        for r in self.resources.values_mut() {
911            if let Some(e) = r.retain_references(&|e| !gone(e)) {
912                let broken = format!(
913                    "{} keeps a reference to {e:?}, which it was told to forget",
914                    r.name()
915                );
916                assert!(!strict, "{broken}");
917                debug_assert!(false, "{broken}");
918            }
919        }
920        let dropped = self.reconcile(graph);
921        self.dropped.append(dropped);
922    }
923
924    pub fn spawn(&mut self) -> Entity {
925        let e = Entity(self.next);
926        self.next = self.next.checked_add(1).expect("more than u32::MAX entities");
927        self.alive.insert(e);
928        e
929    }
930
931    /// Spawn with an explicit id, for readers of serialised worlds that keep the file's ids. Ids must come in
932    /// ascending order (gaps allowed), so ids stay unique: an id at or below one already handed out, or the last id
933    /// (there is none to follow it), is an error and changes nothing.
934    pub fn spawn_at(&mut self, e: Entity) -> Result<Entity, IdError> {
935        if e.0 < self.next {
936            return Err(IdError::NotAscending(e));
937        }
938        let next = e.0.checked_add(1).ok_or(IdError::Exhausted(e))?;
939        self.alive.insert(e);
940        self.next = next;
941        Ok(e)
942    }
943
944    /// Remove an entity and all its components. Returns false if it was not alive.
945    pub fn despawn(&mut self, e: Entity) -> bool {
946        if !self.alive.remove(&e) {
947            return false;
948        }
949        for c in self.columns.values_mut() {
950            c.remove_entity(e);
951        }
952        for col in self.opaque.values_mut() {
953            col.remove(&e);
954        }
955        self.forget_in_resources(|x| x == e, false);
956        true
957    }
958
959    /// Every component of `from`, typed and opaque, moved onto `to`, replacing `to`'s of the same name (`to` keeps
960    /// the others), then `from` despawned: for a pass that swaps one form of an entity for another without knowing
961    /// its components (`select-lod`). `Ok(false)`, and nothing changed, unless both are alive and differ.
962    ///
963    /// Refused, changing nothing, when it would leave data describing one mesh beside another
964    /// ([`Component::GEOMETRY`]): `from` brings a mesh (`core.mesh` or `core.mesh_file`) while `to` keeps such data
965    /// `from` has none of (take `to`'s away first: [`World::remove_mesh`]), or `from` brings such data without a mesh
966    /// onto a `to` that has one.
967    pub fn move_components(&mut self, from: Entity, to: Entity) -> Result<bool, String> {
968        if from == to || !self.alive.contains(&from) || !self.alive.contains(&to) {
969            return Ok(false);
970        }
971        let has_mesh = |e| self.has::<crate::Mesh>(e) || self.has::<crate::MeshFile>(e);
972        let (from_mesh, to_mesh) = (has_mesh(from), has_mesh(to));
973        let mut stale: Vec<&'static str> = self
974            .columns
975            .values()
976            .filter(|c| c.geometry().describes_mesh())
977            .filter(|c| {
978                let (at_from, at_to) = (c.contains(from), c.contains(to));
979                (from_mesh && at_to && !at_from) || (!from_mesh && to_mesh && at_from)
980            })
981            .map(|c| c.name())
982            .collect();
983        if !stale.is_empty() {
984            stale.sort_unstable();
985            return Err(format!(
986                "moving {from:?} onto {to:?} would leave data describing one mesh beside another: {stale:?}"
987            ));
988        }
989        for c in self.columns.values_mut() {
990            c.move_entity(from, to);
991        }
992        for col in self.opaque.values_mut() {
993            if let Some(v) = col.remove(&from) {
994                col.insert(to, v);
995            }
996        }
997        self.alive.remove(&from);
998        self.forget_in_resources(|x| x == from, false);
999        self.note_copy(from, to);
1000        Ok(true)
1001    }
1002
1003    /// A new entity with a copy of every typed and opaque component of `e`; `None` when `e` is not alive. Shallow:
1004    /// references in the copies still name the entities `e`'s did (a pass that needs referenced entities copied too,
1005    /// LOD forms of a prototype, copies them itself).
1006    pub fn duplicate(&mut self, e: Entity) -> Option<Entity> {
1007        if !self.is_alive(e) {
1008            return None;
1009        }
1010        let d = self.spawn();
1011        for c in self.columns.values_mut() {
1012            c.copy_entity(e, d);
1013        }
1014        for values in self.opaque.values_mut() {
1015            if let Some(v) = values.get(&e).cloned() {
1016                values.insert(d, v);
1017            }
1018        }
1019        self.note_copy(e, d);
1020        Some(d)
1021    }
1022
1023    /// Every typed component restated for the axes `resolved` gave values ([`Component::restate`]): the entities some
1024    /// component says are not present in that state, sorted and without repeats, for the caller to remove. The values
1025    /// of every other component are replaced in place. Opaque components hold no clause a pass could read.
1026    pub fn restate_components(&mut self, resolved: &crate::state::Resolved<'_>) -> Vec<Entity> {
1027        let mut absent: Vec<Entity> = self
1028            .columns
1029            .values_mut()
1030            .flat_map(|c| c.restate_all(resolved))
1031            .collect();
1032        absent.sort();
1033        absent.dedup();
1034        absent
1035    }
1036
1037    /// Map `e`'s local space by `l`: every component of `e` through [`Component::apply_linear`]. All or nothing:
1038    /// when a component is [`Linearity::Unsupported`] (opaque components always are) nothing changes and the error
1039    /// names every such component, sorted. Otherwise the names of the components it dropped ([`Linearity::Drop`]),
1040    /// sorted.
1041    pub fn apply_linear(&mut self, e: Entity, l: &crate::Linear) -> Result<Vec<String>, Vec<String>> {
1042        let mut unsupported: Vec<String> = self
1043            .opaque
1044            .iter()
1045            .filter(|(_, values)| values.contains_key(&e))
1046            .map(|(name, _)| name.clone())
1047            .collect();
1048        let mut done = Vec::new();
1049        for (id, c) in &self.columns {
1050            match c.linear(e, l) {
1051                None | Some(Linearity::Invariant) => {}
1052                Some(Linearity::Unsupported) => unsupported.push(c.name().to_string()),
1053                Some(r) => done.push((*id, r)),
1054            }
1055        }
1056        if !unsupported.is_empty() {
1057            unsupported.sort();
1058            return Err(unsupported);
1059        }
1060        let mut dropped = Vec::new();
1061        for (id, r) in done {
1062            if let Some(c) = self.columns.get_mut(&id) {
1063                match r {
1064                    Linearity::Applied(v) => c.put_remapped(e, v),
1065                    Linearity::Drop => {
1066                        c.remove_entity(e);
1067                        dropped.push(c.name().to_string());
1068                    }
1069                    Linearity::Invariant | Linearity::Unsupported => {}
1070                }
1071            }
1072        }
1073        dropped.sort();
1074        Ok(dropped)
1075    }
1076
1077    /// Keep `e`'s per-primitive components in step with its rebuilt mesh: every typed component that follows
1078    /// primitives ([`Component::remap_primitives`]) remapped by `from` (new primitive `i` from old `from[i]`). A pass
1079    /// that splits, reorders or drops a mesh's primitives calls it once, so it need not know the dialects' components.
1080    /// All or nothing: an error (an index a component does not have, or a component refusing the mapping) names the
1081    /// component and changes nothing.
1082    ///
1083    /// An opaque component (bytes a reader carried without a type) can't follow: whether it describes primitives
1084    /// can't be known, so a mapping that changes the list (anything but `0..n` in order) is refused while `e` has
1085    /// one, before anything changes, naming them. The program removes them (a selection, reported) or gives them a
1086    /// typed form first.
1087    pub fn remap_primitives(&mut self, e: Entity, from: &[usize]) -> Result<(), String> {
1088        let identity = from.iter().enumerate().all(|(i, &f)| i == f)
1089            && self
1090                .get::<crate::Mesh>(e)
1091                .is_none_or(|m| m.primitives().len() == from.len());
1092        if !identity {
1093            let mut opaque: Vec<&String> = self
1094                .opaque
1095                .iter()
1096                .filter(|(_, values)| values.contains_key(&e))
1097                .map(|(name, _)| name)
1098                .collect();
1099            if !opaque.is_empty() {
1100                opaque.sort();
1101                return Err(format!(
1102                    "{e:?}: opaque components can't follow a change to its primitives: {opaque:?} (remove them, or \
1103                     give them a typed form, before the pass)"
1104                ));
1105            }
1106        }
1107        let mut done = Vec::new();
1108        // by name, so the error reported is always the same one
1109        let mut columns: Vec<_> = self.columns.iter().collect();
1110        columns.sort_by_key(|(_, c)| c.name());
1111        for (name, c) in columns {
1112            match c.remapped(e, from) {
1113                None if c.contains(e) && c.geometry().describes_mesh() => {
1114                    return Err(format!(
1115                        "{}: holds data per primitive ({:?}) but does not follow a change to them",
1116                        c.name(),
1117                        c.geometry()
1118                    ));
1119                }
1120                None => {}
1121                Some(Ok(v)) => done.push((*name, v)),
1122                Some(Err(m)) => return Err(format!("{}: {m}", c.name())),
1123            }
1124        }
1125        for (name, v) in done {
1126            if let Some(c) = self.columns.get_mut(&name) {
1127                c.put_remapped(e, v);
1128            }
1129        }
1130        Ok(())
1131    }
1132
1133    /// Remap every per-vertex component of `e` ([`Component::remap_vertices`]) for its mesh primitive `primitive`,
1134    /// whose vertices a pass compacted or reordered: new vertex `i` is old vertex `from[i]`. The pass changes the
1135    /// primitive itself and calls this for every other component, so it need not know the dialects' components; it
1136    /// calls it only when the vertices changed. All or nothing: an error (an index a component does not have, or a
1137    /// component refusing the mapping) names the component and changes nothing. Refused, changing nothing, while `e`
1138    /// has an opaque component, as [`World::remap_primitives`] refuses then (whether it describes vertices can't be
1139    /// known).
1140    pub fn remap_vertices(&mut self, e: Entity, primitive: usize, from: &[u32]) -> Result<(), String> {
1141        let done = self.vertex_remapped_components(e, primitive, from)?;
1142        for (name, v) in done {
1143            if let Some(c) = self.columns.get_mut(&name) {
1144                c.put_remapped(e, v);
1145            }
1146        }
1147        Ok(())
1148    }
1149
1150    /// Why [`World::remap_vertices`] would refuse, without changing anything: a pass checks every entity before it
1151    /// changes any.
1152    pub fn check_remap_vertices(&self, e: Entity, primitive: usize, from: &[u32]) -> Result<(), String> {
1153        self.vertex_remapped_components(e, primitive, from).map(|_| ())
1154    }
1155
1156    fn vertex_remapped_components(
1157        &self,
1158        e: Entity,
1159        primitive: usize,
1160        from: &[u32],
1161    ) -> Result<Vec<Blended>, String> {
1162        let mut opaque: Vec<&String> = self
1163            .opaque
1164            .iter()
1165            .filter(|(_, values)| values.contains_key(&e))
1166            .map(|(name, _)| name)
1167            .collect();
1168        if !opaque.is_empty() {
1169            opaque.sort();
1170            return Err(format!(
1171                "{e:?}: opaque components can't follow a change to a primitive's vertices: {opaque:?} (remove them, \
1172                 or give them a typed form, before the pass)"
1173            ));
1174        }
1175        let mut done = Vec::new();
1176        // by name, so the error reported is always the same one
1177        let mut columns: Vec<_> = self.columns.iter().collect();
1178        columns.sort_by_key(|(_, c)| c.name());
1179        for (name, c) in columns {
1180            match c.vertices_remapped(e, primitive, from) {
1181                None if c.contains(e) && c.geometry() == Geometry::PerVertex => {
1182                    return Err(format!(
1183                        "{}: holds data per vertex but does not follow a change to them",
1184                        c.name()
1185                    ));
1186                }
1187                None => {}
1188                Some(Ok(v)) => done.push((*name, v)),
1189                Some(Err(m)) => return Err(format!("{}: {m}", c.name())),
1190            }
1191        }
1192        Ok(done)
1193    }
1194
1195    /// Rebuild every per-vertex component of `e` ([`Component::blend_vertices`]) for its mesh primitive `primitive`,
1196    /// whose vertices a pass made as blends of the old ones: new vertex `i` is `from[i]`. The pass changes the primitive
1197    /// itself and calls this for every other component, so it need not know the dialects' components. All or nothing,
1198    /// like [`World::remap_vertices`]: an error (an index a component does not have, a component that cannot combine
1199    /// its vertices, an opaque component on `e`) names the cause and changes nothing.
1200    pub fn blend_vertices(
1201        &mut self,
1202        e: Entity,
1203        primitive: usize,
1204        from: &[VertexBlend],
1205    ) -> Result<(), String> {
1206        let done = self.blended_components(e, primitive, from)?;
1207        for (name, v) in done {
1208            if let Some(c) = self.columns.get_mut(&name) {
1209                c.put_remapped(e, v);
1210            }
1211        }
1212        Ok(())
1213    }
1214
1215    /// Why [`World::blend_vertices`] would refuse, without changing anything: a pass checks every entity before it
1216    /// changes any.
1217    pub fn check_blend_vertices(
1218        &self,
1219        e: Entity,
1220        primitive: usize,
1221        from: &[VertexBlend],
1222    ) -> Result<(), String> {
1223        self.blended_components(e, primitive, from).map(|_| ())
1224    }
1225
1226    fn blended_components(
1227        &self,
1228        e: Entity,
1229        primitive: usize,
1230        from: &[VertexBlend],
1231    ) -> Result<Vec<Blended>, String> {
1232        let mut opaque: Vec<&String> = self
1233            .opaque
1234            .iter()
1235            .filter(|(_, values)| values.contains_key(&e))
1236            .map(|(name, _)| name)
1237            .collect();
1238        if !opaque.is_empty() {
1239            opaque.sort();
1240            return Err(format!(
1241                "{e:?}: opaque components can't follow a change to a primitive's vertices: {opaque:?} (remove them, \
1242                 or give them a typed form, before the pass)"
1243            ));
1244        }
1245        let mut done = Vec::new();
1246        // by name, so the error reported is always the same one
1247        let mut columns: Vec<_> = self.columns.iter().collect();
1248        columns.sort_by_key(|(_, c)| c.name());
1249        for (name, c) in columns {
1250            match c.vertices_blended(e, primitive, from) {
1251                None if c.contains(e) && c.geometry() == Geometry::PerVertex => {
1252                    return Err(format!(
1253                        "{}: holds data per vertex but cannot combine vertices (it has no blend_vertices)",
1254                        c.name()
1255                    ));
1256                }
1257                None => {}
1258                Some(Ok(v)) => done.push((*name, v)),
1259                Some(Err(m)) => return Err(format!("{}: {m}", c.name())),
1260            }
1261        }
1262        Ok(done)
1263    }
1264
1265    /// Take `e`'s mesh away with every component describing it (each typed component whose [`Component::GEOMETRY`]
1266    /// says it holds something per primitive or vertex) and its file link (`core.mesh_file`, which a load would restore it
1267    /// from): for an entity left drawing nothing, whose per-primitive data would describe no primitive, or one whose
1268    /// geometry another replaces (`select-lod`). A mesh still only in its file (`core.mesh_file` without `core.mesh`, as
1269    /// a world is before its load) goes the same way, with the per-primitive data describing it. Returns the names
1270    /// taken, the mesh's first; none when `e` has neither. Refused, changing nothing, while `e` has an opaque component
1271    /// ([`World::check_remove_mesh`]).
1272    pub fn remove_mesh(&mut self, e: Entity) -> Result<Vec<&'static str>, String> {
1273        let mesh = self.has::<crate::Mesh>(e);
1274        if !mesh && !self.has::<crate::MeshFile>(e) {
1275            return Ok(Vec::new());
1276        }
1277        self.check_remove_mesh(e)?;
1278        let mut names: Vec<&'static str> = mesh.then_some(crate::Mesh::NAME).into_iter().collect();
1279        let mut per_primitive: Vec<(&'static str, TypeId)> = self
1280            .columns
1281            .iter()
1282            .filter(|(_, c)| c.contains(e) && c.geometry().describes_mesh())
1283            .map(|(k, c)| (c.name(), *k))
1284            .collect();
1285        per_primitive.sort();
1286        for (name, k) in per_primitive {
1287            if let Some(c) = self.columns.get_mut(&k) {
1288                c.remove_entity(e);
1289            }
1290            names.push(name);
1291        }
1292        self.remove::<crate::Mesh>(e);
1293        if self.remove::<crate::MeshFile>(e).is_some() {
1294            names.push(crate::MeshFile::NAME);
1295        }
1296        Ok(names)
1297    }
1298
1299    /// Why [`World::remove_mesh`] would refuse `e`, so a pass can check every entity before it changes any: an opaque
1300    /// component on it, as [`World::remap_primitives`] refuses a change to the primitives then (whether it describes
1301    /// primitives can't be known).
1302    pub fn check_remove_mesh(&self, e: Entity) -> Result<(), String> {
1303        let mut opaque: Vec<&String> = self
1304            .opaque
1305            .iter()
1306            .filter(|(_, values)| values.contains_key(&e))
1307            .map(|(name, _)| name)
1308            .collect();
1309        if opaque.is_empty() {
1310            return Ok(());
1311        }
1312        opaque.sort();
1313        Err(format!(
1314            "{e:?}: opaque components can't follow its mesh's removal: {opaque:?} (remove them, or give them a typed \
1315             form, before the pass)"
1316        ))
1317    }
1318
1319    /// The names of `e`'s typed components that hold something per vertex of its mesh ([`Geometry::PerVertex`]), in
1320    /// name order: what a pass that joins primitives into one (whose vertices a source primitive's per-vertex data
1321    /// does not cover) must refuse, since [`Component::remap_vertices`] maps only one source primitive's vertices.
1322    pub fn per_vertex_components(&self, e: Entity) -> Vec<&'static str> {
1323        let mut names: Vec<&'static str> = self
1324            .columns
1325            .values()
1326            .filter(|c| c.contains(e) && c.geometry() == Geometry::PerVertex)
1327            .map(|c| c.name())
1328            .collect();
1329        names.sort_unstable();
1330        names
1331    }
1332
1333    /// Every component of `from`, typed and opaque, copied onto `to`, replacing `to`'s of the same name (`to` keeps
1334    /// the others): for a pass that makes another entity like one it knows only partly (a prototype per tint row,
1335    /// keeping whatever dialect data the reader attached). References are copied as they are. False, and nothing
1336    /// changed, unless both are alive and differ.
1337    pub fn copy_components(&mut self, from: Entity, to: Entity) -> bool {
1338        if from == to || !self.alive.contains(&from) || !self.alive.contains(&to) {
1339            return false;
1340        }
1341        for c in self.columns.values_mut() {
1342            c.copy_entity(from, to);
1343        }
1344        for col in self.opaque.values_mut() {
1345            if let Some(v) = col.get(&from).cloned() {
1346                col.insert(to, v);
1347            }
1348        }
1349        self.note_copy(from, to);
1350        true
1351    }
1352
1353    /// Rebuild `e`'s mesh primitives: `f` returns the new primitives and, for each, the old primitive it comes from (a
1354    /// source may repeat or be absent, as for [`World::remap_primitives`]). The new mesh and every per-primitive
1355    /// component change together, or, when `f` fails or a component cannot follow, nothing does. The one way to change
1356    /// a mesh's primitive list.
1357    pub fn rebuild_primitives(
1358        &mut self,
1359        e: Entity,
1360        f: impl FnOnce(&crate::Mesh) -> Result<(Vec<crate::Primitive>, Vec<usize>), String>,
1361    ) -> Result<(), String> {
1362        let mesh = self
1363            .get::<crate::Mesh>(e)
1364            .ok_or_else(|| format!("{e:?} has no core.mesh"))?;
1365        let (primitives, from) = f(mesh)?;
1366        if primitives.len() != from.len() {
1367            return Err(format!(
1368                "{} primitives with {} sources",
1369                primitives.len(),
1370                from.len()
1371            ));
1372        }
1373        let (old, source) = (mesh.primitives().len(), mesh.id());
1374        if let Some(&i) = from.iter().find(|&&i| i >= old) {
1375            return Err(format!("source primitive {i} of {old}"));
1376        }
1377        self.remap_primitives(e, &from)?;
1378        let made = crate::Mesh::new(primitives);
1379        self.record_rebuild(e, source, old, from, made.id());
1380        self.insert(e, made);
1381        Ok(())
1382    }
1383
1384    /// Edit `e`'s mesh with `f`, which may also rebuild its primitive list: `f` returns `None` when the list keeps its
1385    /// primitives in order (edited in place at most: the mesh stays the same mesh, whatever `f` built to hold them),
1386    /// else, for each primitive now, the one it comes from, as
1387    /// [`World::rebuild_primitives`] (per-primitive components follow, and the conservation diagnostics count the
1388    /// rebuild exactly). False when `e` has no mesh.
1389    ///
1390    /// All or nothing: when `f` fails, its mapping is malformed, or a per-primitive component can't follow it, the
1391    /// mesh and its components are as they were (the mesh is kept while `f` runs, to put back), and the error says
1392    /// why.
1393    pub fn edit_mesh(
1394        &mut self,
1395        e: Entity,
1396        f: impl FnOnce(&mut crate::Mesh) -> Result<Option<Vec<usize>>, String>,
1397    ) -> Result<bool, String> {
1398        // the edit works on a copy: `e` keeps the original until the edit is accepted
1399        let Some(mut mesh) = self.get::<crate::Mesh>(e).cloned() else {
1400            return Ok(false);
1401        };
1402        let (old, source) = (mesh.primitives().len(), mesh.id());
1403        let from = f(&mut mesh)?;
1404        let Some(from) = from else {
1405            let n = mesh.primitives().len();
1406            if n != old {
1407                return Err(format!("{e:?}: {n} primitives from {old} without their sources"));
1408            }
1409            // its primitives kept in order: the same mesh, even when `f` built a new one to hold them
1410            mesh.keep_id(source);
1411            self.insert(e, mesh);
1412            return Ok(true);
1413        };
1414        if mesh.primitives().len() != from.len() || from.iter().any(|&i| i >= old) {
1415            let n = mesh.primitives().len();
1416            return Err(format!(
1417                "{e:?}: {n} primitives with {} sources of {old}",
1418                from.len()
1419            ));
1420        }
1421        // all or nothing: a component that can't follow leaves the components and the original mesh as they were
1422        self.remap_primitives(e, &from)?;
1423        let made = crate::Mesh::new(mesh.into_primitives());
1424        self.record_rebuild(e, source, old, from, made.id());
1425        self.insert(e, made);
1426        Ok(true)
1427    }
1428
1429    /// Record a rebuild of `e`'s mesh `source` (`old` primitives) into `made` for the conservation diagnostics, when
1430    /// they run.
1431    fn record_rebuild(&mut self, e: Entity, source: u64, old: usize, from: Vec<usize>, made: u64) {
1432        if let Some(log) = &mut self.rebuilds {
1433            match log.entry(e) {
1434                std::collections::btree_map::Entry::Vacant(v) => {
1435                    v.insert(Some(Rebuilt {
1436                        source,
1437                        first: old,
1438                        from,
1439                        made,
1440                    }));
1441                }
1442                // compose with the earlier rebuild, unless this one starts from another mesh (replaced in between)
1443                std::collections::btree_map::Entry::Occupied(mut o) => {
1444                    let composed = o.get_mut().take().filter(|r| r.made == source).map(|r| Rebuilt {
1445                        from: from.iter().map(|&i| r.from[i]).collect(),
1446                        made,
1447                        ..r
1448                    });
1449                    *o.get_mut() = composed;
1450                }
1451            }
1452        }
1453    }
1454
1455    /// Start recording primitive rebuilds (the pass manager, around a pass with conservation diagnostics on).
1456    /// Record, until [`World::take_effects`], the resources written and the copies made.
1457    pub(crate) fn start_effects(&mut self) {
1458        self.effects = Some(Effects::default());
1459    }
1460
1461    /// Stop recording and return what was recorded since [`World::start_effects`].
1462    pub(crate) fn take_effects(&mut self) -> Effects {
1463        self.effects.take().unwrap_or_default()
1464    }
1465
1466    fn note_resource_write(&mut self, name: &str) {
1467        if let Some(fx) = &mut self.effects {
1468            fx.resources_written.insert(name.to_owned());
1469        }
1470    }
1471
1472    fn note_copy(&mut self, from: Entity, to: Entity) {
1473        if let Some(fx) = &mut self.effects {
1474            fx.copies.push((from, to));
1475        }
1476    }
1477
1478    pub(crate) fn start_rebuild_log(&mut self) {
1479        self.rebuilds = Some(BTreeMap::new());
1480    }
1481
1482    /// Stop recording and return what was recorded since [`World::start_rebuild_log`].
1483    pub(crate) fn take_rebuild_log(&mut self) -> RebuildLog {
1484        self.rebuilds.take().unwrap_or_default()
1485    }
1486
1487    pub fn is_alive(&self, e: Entity) -> bool {
1488        self.alive.contains(&e)
1489    }
1490
1491    /// The index the next spawned entity gets: an entity with an index at or above it was made after this call
1492    /// (ids are handed out in order and never reused; a part loaded with [`World::subset`] keeps its planning world's,
1493    /// so what a pass makes in it is told from what was loaded).
1494    pub fn next_index(&self) -> u32 {
1495        self.next
1496    }
1497
1498    /// Reserve every index below `next` without creating entities. A freshly re-read subset that will be absorbed
1499    /// into a newer World uses that World's `next_index`, so passes cannot reuse its other entities' ids.
1500    /// Never rewinds the allocator or changes which entities are alive.
1501    pub fn reserve_indices_before(&mut self, next: u32) {
1502        self.next = self.next.max(next);
1503    }
1504
1505    /// The entities `e`'s components refer to (not its resources'), in no particular order, repeats possible.
1506    pub fn references(&self, e: Entity) -> Vec<Entity> {
1507        let mut out = Vec::new();
1508        for c in self.columns.values() {
1509            c.references(e, &mut out);
1510        }
1511        out
1512    }
1513
1514    /// The entities nothing in the world refers to (through any entity's components): its independent content,
1515    /// placements, markers, standalone soups, rather than the prototypes, materials and textures they reach.
1516    pub fn unreferenced(&self) -> BTreeSet<Entity> {
1517        let mut referenced = BTreeSet::new();
1518        for &e in &self.alive {
1519            referenced.extend(self.references(e));
1520        }
1521        self.alive
1522            .iter()
1523            .copied()
1524            .filter(|e| !referenced.contains(e))
1525            .collect()
1526    }
1527
1528    /// `roots` and every alive entity they reach through [`Component::references`], transitively. Opaque
1529    /// components declare no references: an entity's opaque components travel with it in [`World::subset`], but
1530    /// nothing they may name is followed.
1531    pub fn closure(&self, roots: impl IntoIterator<Item = Entity>) -> BTreeSet<Entity> {
1532        let mut seen = BTreeSet::new();
1533        let mut todo: Vec<Entity> = roots.into_iter().collect();
1534        let mut out = Vec::new();
1535        while let Some(e) = todo.pop() {
1536            if !self.alive.contains(&e) || !seen.insert(e) {
1537                continue;
1538            }
1539            for c in self.columns.values() {
1540                c.references(e, &mut out);
1541            }
1542            todo.append(&mut out);
1543        }
1544        seen
1545    }
1546
1547    /// Every typed reference ([`Component::references`]) to an entity of `targets`: (component name, the entity holding
1548    /// it, the entity referred to), sorted. Opaque components declare no references, as in [`World::closure`].
1549    pub(crate) fn references_to(&self, targets: &BTreeSet<Entity>) -> Vec<(&'static str, Entity, Entity)> {
1550        let mut edges = Vec::new();
1551        let mut refs = Vec::new();
1552        for c in self.columns.values() {
1553            for source in c.entities() {
1554                refs.clear();
1555                c.references(source, &mut refs);
1556                edges.extend(
1557                    refs.iter()
1558                        .filter(|r| targets.contains(r))
1559                        .map(|&target| (c.name(), source, target)),
1560                );
1561            }
1562        }
1563        edges.sort_unstable();
1564        edges.dedup();
1565        edges
1566    }
1567
1568    /// A world of only `keep`'s entities (those alive) with all their components, typed and opaque, under the
1569    /// same ids, and every resource (forgetting its references to entities left out). Entities spawned in it get ids
1570    /// above every id of `self`.
1571    ///
1572    /// For a selection that keeps everything the world's render graph draws with: one that leaves some of it out drops
1573    /// what [`World::part`] states, and panics naming it (take that part with [`World::part`] and count it).
1574    #[track_caller]
1575    pub fn subset(&self, keep: &BTreeSet<Entity>) -> World {
1576        let Part { world, dropped } = self.part(keep);
1577        assert!(
1578            dropped.is_empty(),
1579            "World::subset left out what the render graph draws with, and dropped {dropped}: take the part with \
1580             World::part and count what it drops"
1581        );
1582        world
1583    }
1584
1585    /// [`World::subset`]'s world, and what it dropped to stay whole: the render graph's steps that drew with an entity
1586    /// left out, and the step bindings and step draws naming draws only they made ([`Dropped`]).
1587    pub fn part(&self, keep: &BTreeSet<Entity>) -> Part {
1588        let alive: BTreeSet<Entity> = self.alive.intersection(keep).copied().collect();
1589        let (resources, graph) = self.resources_for(&alive);
1590        let mut world = World {
1591            next: self.next,
1592            resources,
1593            alive,
1594            columns: self
1595                .columns
1596                .iter()
1597                .map(|(k, v)| (*k, v.subset_box(keep)))
1598                .collect(),
1599            names: self.names.clone(),
1600            opaque: self
1601                .opaque
1602                .iter()
1603                .map(|(k, v)| (k.clone(), subset_of(v, keep)))
1604                .collect(),
1605            opaque_resources: self.opaque_resources.clone(),
1606            rebuilds: None,
1607            effects: None,
1608            dropped: Dropped::default(),
1609        };
1610        let dropped = world.reconcile(graph);
1611        Part { world, dropped }
1612    }
1613
1614    /// Move `keep`'s entities (those alive), with all their components, out into a world of their own: what
1615    /// [`World::subset`] copies, without copying. The part has every resource (copied, as a subset's) and spawns ids
1616    /// above every id of `self`, as a subset does; [`World::absorb`] moves it back. This world's resources keep their
1617    /// references to the moved entities, which come back with the part.
1618    ///
1619    /// A loss is data that leaves the world and does not arrive. The part's render graph is a copy, and this world
1620    /// keeps every step: the steps pruned from the copy (they draw with entities the part lacks) are not a loss, and
1621    /// [`World::split_part`] counts them. The step bindings and step draws stripped from the moved entities (they named
1622    /// draws only those steps made) leave with the entities and do not come back on [`World::absorb`]: a loss, and
1623    /// split_off panics naming it (take the part with [`World::split_part`] and count it).
1624    #[track_caller]
1625    pub fn split_off(&mut self, keep: &BTreeSet<Entity>) -> World {
1626        let Part { world, dropped } = self.split_part(keep);
1627        assert!(
1628            dropped.step_bindings.is_empty() && dropped.step_draws.is_empty(),
1629            "World::split_off stripped from the entities it moved what named the draws of render graph steps the part \
1630             could not keep, and the part dropped {dropped}: take it with World::split_part and count what it drops"
1631        );
1632        world
1633    }
1634
1635    /// [`World::split_off`]'s part, and what it dropped to stay whole ([`World::part`]). The render graph steps in it
1636    /// are pruned from the part's copy (this world keeps them all): counted, not a loss. The step bindings and step
1637    /// draws in it were stripped from the moved entities: a loss ([`World::split_off`]), since absorbed back the
1638    /// entities hold none of them.
1639    pub fn split_part(&mut self, keep: &BTreeSet<Entity>) -> Part {
1640        let alive: BTreeSet<Entity> = self.alive.intersection(keep).copied().collect();
1641        for e in &alive {
1642            self.alive.remove(e);
1643        }
1644        let (resources, graph) = self.resources_for(&alive);
1645        let mut world = World {
1646            next: self.next,
1647            columns: self
1648                .columns
1649                .iter_mut()
1650                .map(|(k, v)| (*k, v.split_off_box(&alive)))
1651                .collect(),
1652            names: self.names.clone(),
1653            opaque: self
1654                .opaque
1655                .iter_mut()
1656                .map(|(k, v)| {
1657                    let part = alive
1658                        .iter()
1659                        .filter_map(|e| v.remove(e).map(|o| (*e, o)))
1660                        .collect();
1661                    (k.clone(), part)
1662                })
1663                .collect(),
1664            resources,
1665            alive,
1666            opaque_resources: self.opaque_resources.clone(),
1667            rebuilds: None,
1668            effects: None,
1669            dropped: Dropped::default(),
1670        };
1671        let dropped = world.reconcile(graph);
1672        Part { world, dropped }
1673    }
1674
1675    /// Move every entity of `part` (a [`World::split_off`] of this world) back in, with its components; `part`'s
1676    /// resources are dropped. Ids the part spawned and despawned again were never alive here and are not reserved, so
1677    /// a split, written and absorbed part leaves this world as it was. An entity of `part` that is alive here is an
1678    /// error, and so is an id with none after it; either changes nothing.
1679    pub fn absorb(&mut self, part: World) -> Result<(), IdError> {
1680        if let Some(e) = part.alive.iter().find(|e| self.alive.contains(e)) {
1681            return Err(IdError::Alive(*e));
1682        }
1683        // ids the part spawned and despawned again are not taken here: the next id stays this world's own,
1684        // unless the part brings back an entity at or above it
1685        let next = match part.alive.last() {
1686            Some(last) => self
1687                .next
1688                .max(last.0.checked_add(1).ok_or(IdError::Exhausted(*last))?),
1689            None => self.next,
1690        };
1691        self.next = next;
1692        self.alive.extend(part.alive);
1693        for (k, col) in part.columns {
1694            match self.columns.get_mut(&k) {
1695                Some(mine) => mine.absorb(col),
1696                None => {
1697                    self.names.insert(col.name(), k);
1698                    self.columns.insert(k, col);
1699                }
1700            }
1701        }
1702        for (k, mut col) in part.opaque {
1703            self.opaque.entry(k).or_default().append(&mut col);
1704        }
1705        Ok(())
1706    }
1707
1708    /// Despawn every entity outside `keep`: in place, what [`World::subset`] copies.
1709    pub fn retain(&mut self, keep: &BTreeSet<Entity>) {
1710        self.alive.retain(|e| keep.contains(e));
1711        self.forget_in_resources(|e| !keep.contains(&e), true);
1712        for c in self.columns.values_mut() {
1713            c.retain(keep);
1714        }
1715        for col in self.opaque.values_mut() {
1716            col.retain(|e, _| keep.contains(e));
1717        }
1718    }
1719
1720    /// Alive entities in ascending order.
1721    pub fn entities(&self) -> impl DoubleEndedIterator<Item = Entity> + '_ {
1722        self.alive.iter().copied()
1723    }
1724
1725    pub fn entity_count(&self) -> usize {
1726        self.alive.len()
1727    }
1728
1729    /// Give component type `T` its name in this world, or say what holds it: another type, a resource or an opaque
1730    /// component (the same answer whichever came first).
1731    fn claim<T: Component>(&mut self) -> Result<(), NameClash> {
1732        let id = TypeId::of::<T>();
1733        let clash = |held| NameClash {
1734            name: T::NAME.to_owned(),
1735            held,
1736        };
1737        match self.names.get(T::NAME) {
1738            Some(&owner) if owner == id => return Ok(()),
1739            Some(_) => return Err(clash("another component type's name")),
1740            None => {}
1741        }
1742        if self.is_resource_name(T::NAME) {
1743            return Err(clash("a resource's name"));
1744        }
1745        if self.opaque.contains_key(T::NAME) {
1746            return Err(clash("an opaque component's name"));
1747        }
1748        self.names.insert(T::NAME, id);
1749        Ok(())
1750    }
1751
1752    fn column_for<T: Component>(&mut self) -> &mut Column<T> {
1753        self.columns
1754            .entry(TypeId::of::<T>())
1755            .or_insert_with(|| Box::new(Column::<T>::default()))
1756            .as_any_mut()
1757            .downcast_mut::<Column<T>>()
1758            .expect("column type matches its TypeId")
1759    }
1760
1761    fn register<T: Component>(&mut self) -> &mut Column<T> {
1762        if let Err(clash) = self.claim::<T>() {
1763            panic!("{clash}");
1764        }
1765        self.column_for::<T>()
1766    }
1767
1768    /// Attach (or replace) a component. Panics if the entity is not alive: attaching to a dead entity is a bug.
1769    /// Replacing a value an entity keeps is an in-place edit to the pass manager, as through [`World::get_mut`]:
1770    /// declared in [`crate::pass::Pass::modifies`], not checked.
1771    pub fn insert<T: Component>(&mut self, e: Entity, value: T) -> Option<T> {
1772        assert!(self.alive.contains(&e), "insert {} on dead entity {e:?}", T::NAME);
1773        self.register::<T>().insert(e, value)
1774    }
1775
1776    /// [`World::insert`] for a name that may be taken: a clash (another type, a resource or an opaque component holds
1777    /// the name) is an error and changes nothing, whichever of the two came first. For a reader that puts what a file
1778    /// names in the world; [`World::insert`] is for a name the program chose and a clash there is its bug.
1779    pub fn try_insert<T: Component>(&mut self, e: Entity, value: T) -> Result<Option<T>, NameClash> {
1780        assert!(self.alive.contains(&e), "insert {} on dead entity {e:?}", T::NAME);
1781        self.claim::<T>()?;
1782        Ok(self.column_for::<T>().insert(e, value))
1783    }
1784
1785    pub fn remove<T: Component>(&mut self, e: Entity) -> Option<T> {
1786        self.column_mut_existing::<T>()?.remove(e)
1787    }
1788
1789    pub fn get<T: Component>(&self, e: Entity) -> Option<&T> {
1790        self.column::<T>()?.get(e)
1791    }
1792
1793    /// `e`'s `T` as a shared handle: the world's own value, not a copy ([`Column::get_shared`]). A later write to it
1794    /// through the world copies it first, so the handle keeps what it was given; a holder that only reads (a renderer
1795    /// uploading a texture) keeps the bytes without a second copy.
1796    pub fn get_shared<T: Component>(&self, e: Entity) -> Option<Arc<T>> {
1797        self.column::<T>()?.get_shared(e)
1798    }
1799
1800    /// `e`'s `T` taken out as the shared handle: the world's own value, never a copy, where [`World::remove`] copies a
1801    /// value something else still shares. For a holder of [`World::get_shared`] handles that takes over their keeping
1802    /// (a renderer that releases a texture's levels once its image is on the GPU): the bytes go when the last handle does.
1803    pub fn remove_shared<T: Component>(&mut self, e: Entity) -> Option<Arc<T>> {
1804        self.column_mut_existing::<T>()?.remove_shared(e)
1805    }
1806
1807    pub fn get_mut<T: Component>(&mut self, e: Entity) -> Option<&mut T> {
1808        self.column_mut_existing::<T>()?.get_mut(e)
1809    }
1810
1811    pub fn has<T: Component>(&self, e: Entity) -> bool {
1812        self.column::<T>().is_some_and(|c| c.contains(e))
1813    }
1814
1815    /// The column of `T`, if any entity ever had one.
1816    pub fn column<T: Component>(&self) -> Option<&Column<T>> {
1817        self.columns
1818            .get(&TypeId::of::<T>())
1819            .map(|c| c.as_any().downcast_ref().expect("column type"))
1820    }
1821
1822    fn column_mut_existing<T: Component>(&mut self) -> Option<&mut Column<T>> {
1823        self.columns
1824            .get_mut(&TypeId::of::<T>())
1825            .map(|c| c.as_any_mut().downcast_mut().expect("column type"))
1826    }
1827
1828    /// Mutable access to the values of `T` (entities cannot be added or removed through it).
1829    pub fn column_mut<T: Component>(&mut self) -> Option<ColumnMut<'_, T>> {
1830        self.column_mut_existing::<T>().map(ColumnMut)
1831    }
1832
1833    /// Two different columns at once, e.g. writing `B` while reading `A` of the same entities.
1834    /// Panics if `A` and `B` are the same type.
1835    pub fn columns2_mut<A: Component, B: Component>(
1836        &mut self,
1837    ) -> (Option<ColumnMut<'_, A>>, Option<ColumnMut<'_, B>>) {
1838        let (a, b) = (TypeId::of::<A>(), TypeId::of::<B>());
1839        assert!(a != b, "columns2_mut needs two different component types");
1840        let (mut ca, mut cb) = (None, None);
1841        for (k, c) in &mut self.columns {
1842            if *k == a {
1843                ca = Some(c);
1844            } else if *k == b {
1845                cb = Some(c);
1846            }
1847        }
1848        (
1849            ca.map(|c| ColumnMut(c.as_any_mut().downcast_mut().expect("column type"))),
1850            cb.map(|c| ColumnMut(c.as_any_mut().downcast_mut().expect("column type"))),
1851        )
1852    }
1853
1854    /// Entities with `T`, in ascending order.
1855    pub fn iter<T: Component>(&self) -> impl DoubleEndedIterator<Item = (Entity, &T)> {
1856        self.column::<T>().into_iter().flat_map(|c| c.iter())
1857    }
1858
1859    /// Entities with both `A` and `B`, in ascending order.
1860    pub fn iter2<A: Component, B: Component>(&self) -> impl Iterator<Item = (Entity, &A, &B)> {
1861        let b = self.column::<B>();
1862        self.iter::<A>()
1863            .filter_map(move |(e, va)| Some((e, va, b?.get(e)?)))
1864    }
1865
1866    /// Names of every component kind present (typed and opaque), sorted.
1867    pub fn component_names(&self) -> Vec<&str> {
1868        let mut names: Vec<&str> = self
1869            .columns
1870            .values()
1871            .filter(|c| c.len() > 0)
1872            .map(|c| c.name())
1873            .collect();
1874        names.extend(
1875            self.opaque
1876                .iter()
1877                .filter(|(_, c)| !c.is_empty())
1878                .map(|(n, _)| n.as_str()),
1879        );
1880        names.sort_unstable();
1881        names.dedup();
1882        names
1883    }
1884
1885    /// Whether any entity has a component of this name (typed or opaque).
1886    pub fn has_component_named(&self, name: &str) -> bool {
1887        self.columns.values().any(|c| c.name() == name && c.len() > 0)
1888            || self.opaque.get(name).is_some_and(|c| !c.is_empty())
1889    }
1890
1891    /// Entities that have a component of this name (typed or opaque), ascending.
1892    pub fn entities_named(&self, name: &str) -> Vec<Entity> {
1893        let mut out: Vec<Entity> = self
1894            .columns
1895            .values()
1896            .filter(|c| c.name() == name)
1897            .flat_map(|c| c.entities())
1898            .collect();
1899        if let Some(col) = self.opaque.get(name) {
1900            out.extend(col.keys().copied());
1901        }
1902        out.sort_unstable();
1903        out.dedup();
1904        out
1905    }
1906
1907    /// Every typed component's [`Component::verify`], and that each entity it refers to ([`Component::references`])
1908    /// is alive: (component name, entity, message) for each failure, by name then entity.
1909    pub fn verify_components(&self) -> Vec<(&'static str, Entity, String)> {
1910        let mut out: Vec<(&'static str, Entity, String)> = self
1911            .columns
1912            .values()
1913            .flat_map(|c| c.verify(self).into_iter().map(|(e, m)| (c.name(), e, m)))
1914            .collect();
1915        out.sort_by(|a, b| (a.0, a.1).cmp(&(b.0, b.1)));
1916        out
1917    }
1918
1919    /// Every typed resource's [`Resource::verify`], and that each entity it refers to is alive: (resource name,
1920    /// message) for each failure, by name.
1921    pub fn verify_resources(&self) -> Vec<(&'static str, String)> {
1922        let mut out = Vec::new();
1923        let mut refs = Vec::new();
1924        for r in self.resources.values() {
1925            if let Err(m) = r.verify(self) {
1926                out.push((r.name(), m));
1927            }
1928            refs.clear();
1929            r.references(&mut refs);
1930            if let Some(e) = refs.iter().find(|e| !self.alive.contains(e)) {
1931                out.push((r.name(), format!("refers to {e:?}, which is not alive")));
1932            }
1933        }
1934        out.sort();
1935        out
1936    }
1937
1938    /// Bulk payload bytes by component name, for the names that hold any: typed components'
1939    /// [`Component::payload_bytes`] and opaque byte payloads.
1940    pub fn payload_bytes(&self) -> BTreeMap<&str, u64> {
1941        let mut out: BTreeMap<&str, u64> = BTreeMap::new();
1942        for c in self.columns.values() {
1943            let n = c.payload_bytes();
1944            if n > 0 {
1945                *out.entry(c.name()).or_default() += n;
1946            }
1947        }
1948        for (name, col) in &self.opaque {
1949            let n: u64 = col
1950                .values()
1951                .map(|o| match &o.data {
1952                    OpaqueData::Bytes(b) => b.len() as u64,
1953                    OpaqueData::Json(_) => 0,
1954                })
1955                .sum();
1956            if n > 0 {
1957                *out.entry(name.as_str()).or_default() += n;
1958            }
1959        }
1960        out
1961    }
1962
1963    /// Names of the components (typed and opaque) this entity has, sorted.
1964    pub fn component_names_of(&self, e: Entity) -> Vec<&str> {
1965        let mut names: Vec<&str> = self
1966            .columns
1967            .values()
1968            .filter(|c| c.contains(e))
1969            .map(|c| c.name())
1970            .collect();
1971        names.extend(
1972            self.opaque
1973                .iter()
1974                .filter(|(_, c)| c.contains_key(&e))
1975                .map(|(n, _)| n.as_str()),
1976        );
1977        names.sort_unstable();
1978        names
1979    }
1980
1981    /// Whether this entity has a component of this name (typed or opaque).
1982    pub fn entity_has_named(&self, e: Entity, name: &str) -> bool {
1983        self.columns.values().any(|c| c.name() == name && c.contains(e))
1984            || self.opaque.get(name).is_some_and(|c| c.contains_key(&e))
1985    }
1986
1987    /// Every component of an entity as JSON, sorted by name: typed ones through [`Component::to_json`], opaque JSON
1988    /// ones as they are. Components without a JSON view (opaque bytes, typed ones that are not shown) are listed with
1989    /// `None`, so callers can count them.
1990    ///
1991    /// Fails, naming the component and the entity, when a view would lose a value (a non-finite float).
1992    pub fn components_json(&self, e: Entity) -> Result<Vec<ComponentJson<'_>>, ComponentJsonError> {
1993        let mut out = Vec::new();
1994        for c in self.columns.values() {
1995            if let Some(v) = c.json(e) {
1996                out.push(ComponentJson {
1997                    name: c.name(),
1998                    version: c.version(),
1999                    value: v.map_err(|err| ComponentJsonError {
2000                        component: c.name().to_owned(),
2001                        entity: Some(e),
2002                        message: err.0,
2003                    })?,
2004                });
2005            }
2006        }
2007        for (name, col) in &self.opaque {
2008            if let Some(o) = col.get(&e) {
2009                out.push(ComponentJson {
2010                    name: name.as_str(),
2011                    version: o.version,
2012                    value: opaque_json(o),
2013                });
2014            }
2015        }
2016        out.sort_by(|a, b| a.name.cmp(b.name));
2017        Ok(out)
2018    }
2019
2020    /// Every resource (typed and opaque) as JSON, sorted by name; as [`World::components_json`].
2021    pub fn resources_json(&self) -> Result<Vec<ComponentJson<'_>>, ComponentJsonError> {
2022        let mut out = Vec::new();
2023        for r in self.resources.values() {
2024            out.push(ComponentJson {
2025                name: r.name(),
2026                version: r.version(),
2027                value: r.json().map_err(|err| ComponentJsonError {
2028                    component: r.name().to_owned(),
2029                    entity: None,
2030                    message: err.0,
2031                })?,
2032            });
2033        }
2034        for (name, o) in &self.opaque_resources {
2035            out.push(ComponentJson {
2036                name: name.as_str(),
2037                version: o.version,
2038                value: opaque_json(o),
2039            });
2040        }
2041        out.sort_by(|a, b| a.name.cmp(b.name));
2042        Ok(out)
2043    }
2044
2045    /// Every component (typed and opaque) with its schema version, for debugging tools: `f(name, version, entity,
2046    /// value)`, by name then entity. Values are shown through `Debug`, which is not a format: its text may change
2047    /// between builds and toolchains, so nothing that is gated, cached or compared across builds may depend on it.
2048    pub fn visit_components_debug(&self, f: &mut dyn FnMut(&str, u32, Entity, &dyn fmt::Debug)) {
2049        enum Kind<'a> {
2050            Typed(&'a dyn AnyColumn),
2051            Opaque(&'a BTreeMap<Entity, Opaque>),
2052        }
2053        let mut kinds: Vec<(&str, Kind<'_>)> = self
2054            .columns
2055            .values()
2056            .filter(|c| c.len() > 0)
2057            .map(|c| (c.name(), Kind::Typed(c.as_ref())))
2058            .collect();
2059        kinds.extend(
2060            self.opaque
2061                .iter()
2062                .filter(|(_, c)| !c.is_empty())
2063                .map(|(n, c)| (n.as_str(), Kind::Opaque(c))),
2064        );
2065        // a name is typed or opaque, never both (each insert refuses the other kind's names)
2066        kinds.sort_unstable_by_key(|(n, _)| *n);
2067        for (name, kind) in kinds {
2068            match kind {
2069                Kind::Typed(c) => {
2070                    let version = c.version();
2071                    c.visit_debug(&mut |e, v| f(name, version, e, v));
2072                }
2073                Kind::Opaque(c) => {
2074                    for (e, o) in c {
2075                        f(name, o.version, *e, &o.data);
2076                    }
2077                }
2078            }
2079        }
2080    }
2081
2082    /// Every resource (typed and opaque) with its schema version, by name, through `Debug`; as
2083    /// [`World::visit_components_debug`], for debugging tools only.
2084    pub fn visit_resources_debug(&self, f: &mut dyn FnMut(&str, u32, &dyn fmt::Debug)) {
2085        let mut all: Vec<(&str, u32, &dyn fmt::Debug)> = self
2086            .resources
2087            .values()
2088            .map(|r| (r.name(), r.version(), r.debug()))
2089            .collect();
2090        all.extend(
2091            self.opaque_resources
2092                .iter()
2093                .map(|(n, o)| (n.as_str(), o.version, &o.data as &dyn fmt::Debug)),
2094        );
2095        all.sort_unstable_by_key(|(n, _, _)| *n);
2096        for (name, version, value) in all {
2097            f(name, version, value);
2098        }
2099    }
2100
2101    // ---- opaque components -------------------------------------------------------------------------------------
2102
2103    /// Attach a component this build does not model. A name a typed component or a resource holds (in this world so
2104    /// far) is an error and changes nothing: a reader that knows the type must decode it. A typed insert of a name
2105    /// held here by an opaque component is refused the same way ([`World::try_insert`]).
2106    pub fn insert_opaque(
2107        &mut self,
2108        e: Entity,
2109        name: &str,
2110        value: Opaque,
2111    ) -> Result<Option<Opaque>, NameClash> {
2112        assert!(self.alive.contains(&e), "insert {name} on dead entity {e:?}");
2113        let clash = |held| NameClash {
2114            name: name.to_owned(),
2115            held,
2116        };
2117        if self.names.contains_key(name) {
2118            return Err(clash("a typed component's name (decode it instead)"));
2119        }
2120        if self.is_resource_name(name) {
2121            return Err(clash("a resource's name"));
2122        }
2123        Ok(self.opaque.entry(name.to_owned()).or_default().insert(e, value))
2124    }
2125
2126    pub fn get_opaque(&self, e: Entity, name: &str) -> Option<&Opaque> {
2127        self.opaque.get(name)?.get(&e)
2128    }
2129
2130    pub fn remove_opaque(&mut self, e: Entity, name: &str) -> Option<Opaque> {
2131        self.opaque.get_mut(name)?.remove(&e)
2132    }
2133
2134    /// Every opaque component kind with its values, by name then entity.
2135    pub fn opaque_components(&self) -> impl Iterator<Item = (&str, &BTreeMap<Entity, Opaque>)> {
2136        self.opaque.iter().map(|(n, c)| (n.as_str(), c))
2137    }
2138
2139    // ---- resources ---------------------------------------------------------------------------------------------
2140
2141    /// Insert (or replace) a resource. Panics if a component has its name: a name is a component's or a resource's,
2142    /// not both, so pass declarations, which list both, stay unambiguous. [`World::try_insert_resource`] refuses
2143    /// instead.
2144    pub fn insert_resource<T: Resource>(&mut self, value: T) -> Option<T> {
2145        match self.try_insert_resource(value) {
2146            Ok(old) => old,
2147            Err(clash) => panic!("{clash}"),
2148        }
2149    }
2150
2151    /// [`World::insert_resource`] for a name that may be taken: a component's name is an error and changes nothing.
2152    pub fn try_insert_resource<T: Resource>(&mut self, value: T) -> Result<Option<T>, NameClash> {
2153        if self.is_component_name(T::NAME) {
2154            return Err(NameClash {
2155                name: T::NAME.to_owned(),
2156                held: "a component's name",
2157            });
2158        }
2159        let Some(old) = self.resources.insert(TypeId::of::<T>(), Box::new(value)) else {
2160            return Ok(None);
2161        };
2162        self.note_resource_write(T::NAME);
2163        let any: Box<dyn Any> = old;
2164        Ok(any.downcast::<T>().ok().map(|b| *b))
2165    }
2166
2167    pub fn resource<T: Resource>(&self) -> Option<&T> {
2168        self.resources
2169            .get(&TypeId::of::<T>())
2170            .and_then(|r| r.as_any().downcast_ref())
2171    }
2172
2173    /// Borrowed to write: a pass that does declares the name in [`crate::pass::Pass::modifies`].
2174    pub fn resource_mut<T: Resource>(&mut self) -> Option<&mut T> {
2175        if self.resources.contains_key(&TypeId::of::<T>()) {
2176            self.note_resource_write(T::NAME);
2177        }
2178        self.resources
2179            .get_mut(&TypeId::of::<T>())
2180            .and_then(|r| r.as_any_mut().downcast_mut())
2181    }
2182
2183    /// Lend resource `T` read-only to `f` while `f` changes the rest of the world, then put it back as it was: a
2184    /// borrow, not a write, so the pass manager records none. `f` gets `None` when the world holds no `T`. Panics if
2185    /// `f` puts a `T` of its own into the world while one is lent: the one lent is the one that goes back.
2186    pub fn resource_scope<T: Resource, R>(&mut self, f: impl FnOnce(&mut World, Option<&T>) -> R) -> R {
2187        let held = self.resources.remove(&TypeId::of::<T>());
2188        let out = f(self, held.as_ref().and_then(|b| b.as_any().downcast_ref::<T>()));
2189        if let Some(b) = held {
2190            let replaced = self.resources.insert(TypeId::of::<T>(), b);
2191            assert!(
2192                replaced.is_none(),
2193                "{} was inserted while lent by resource_scope",
2194                T::NAME
2195            );
2196        }
2197        out
2198    }
2199
2200    pub fn remove_resource<T: Resource>(&mut self) -> Option<T> {
2201        let old = self.resources.remove(&TypeId::of::<T>())?;
2202        if let Some(fx) = &mut self.effects {
2203            fx.resources_removed.insert(T::NAME.to_owned());
2204        }
2205        let any: Box<dyn Any> = old;
2206        any.downcast::<T>().ok().map(|b| *b)
2207    }
2208
2209    /// As [`World::try_insert_resource`], for a resource this build does not model: a component's name is an error.
2210    pub fn insert_opaque_resource(&mut self, name: &str, value: Opaque) -> Result<Option<Opaque>, NameClash> {
2211        if self.is_component_name(name) {
2212            return Err(NameClash {
2213                name: name.to_owned(),
2214                held: "a component's name",
2215            });
2216        }
2217        let old = self.opaque_resources.insert(name.to_owned(), value);
2218        if old.is_some() {
2219            self.note_resource_write(name);
2220        }
2221        Ok(old)
2222    }
2223
2224    /// Names of every resource (typed and opaque), sorted.
2225    pub fn resource_names(&self) -> Vec<&str> {
2226        let mut names: Vec<&str> = self
2227            .resources
2228            .values()
2229            .map(|r| r.name())
2230            .chain(self.opaque_resources.keys().map(String::as_str))
2231            .collect();
2232        names.sort_unstable();
2233        names.dedup();
2234        names
2235    }
2236
2237    fn is_resource_name(&self, name: &str) -> bool {
2238        self.resources.values().any(|r| r.name() == name) || self.opaque_resources.contains_key(name)
2239    }
2240
2241    /// A component type or an opaque component has ever been stored under `name`.
2242    fn is_component_name(&self, name: &str) -> bool {
2243        self.names.contains_key(name) || self.opaque.contains_key(name)
2244    }
2245
2246    pub fn opaque_resources(&self) -> impl Iterator<Item = (&str, &Opaque)> {
2247        self.opaque_resources.iter().map(|(n, v)| (n.as_str(), v))
2248    }
2249}
2250
2251fn opaque_json(o: &Opaque) -> Option<serde_json::Value> {
2252    match &o.data {
2253        OpaqueData::Json(v) => Some(v.clone()),
2254        OpaqueData::Bytes(_) => None,
2255    }
2256}
2257
2258/// Mutable access to one column's values without changing which entities it holds.
2259#[derive(Debug)]
2260pub struct ColumnMut<'w, T>(&'w mut Column<T>);
2261
2262impl<T> ColumnMut<'_, T> {
2263    pub fn get(&self, e: Entity) -> Option<&T> {
2264        self.0.get(e)
2265    }
2266    pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Entity, &T)> + ExactSizeIterator {
2267        self.0.iter()
2268    }
2269    pub fn len(&self) -> usize {
2270        self.0.len()
2271    }
2272    pub fn is_empty(&self) -> bool {
2273        self.0.is_empty()
2274    }
2275}
2276
2277impl<T: Clone> ColumnMut<'_, T> {
2278    pub fn get_mut(&mut self, e: Entity) -> Option<&mut T> {
2279        self.0.get_mut(e)
2280    }
2281    pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = (Entity, &mut T)> + ExactSizeIterator {
2282        self.0.iter_mut()
2283    }
2284}
2285
2286#[cfg(test)]
2287mod tests {
2288    use super::*;
2289
2290    #[derive(Clone, Debug, PartialEq)]
2291    struct A(u32);
2292    impl Component for A {
2293        const NAME: &'static str = "test.a";
2294        const GEOMETRY: crate::Geometry = crate::Geometry::None;
2295    }
2296    #[derive(Clone, Debug, PartialEq)]
2297    struct B(&'static str);
2298    impl Component for B {
2299        const NAME: &'static str = "test.b";
2300        const GEOMETRY: crate::Geometry = crate::Geometry::None;
2301    }
2302    #[derive(Clone, Debug, PartialEq)]
2303    struct Same;
2304    impl Component for Same {
2305        const NAME: &'static str = "test.a";
2306        const GEOMETRY: crate::Geometry = crate::Geometry::None;
2307    }
2308    #[derive(Clone, Debug, PartialEq)]
2309    struct R(i32);
2310    impl Resource for R {
2311        const NAME: &'static str = "test.r";
2312    }
2313
2314    #[test]
2315    fn a_shared_value_is_the_world_s_own_and_keeps_what_it_was_given() {
2316        let mut w = World::new();
2317        let e = w.spawn();
2318        w.insert(e, A(1));
2319        let shared = w.get_shared::<A>(e).unwrap();
2320        assert!(
2321            std::ptr::eq(shared.as_ref(), w.get::<A>(e).unwrap()),
2322            "the handle is the world's value, not a copy"
2323        );
2324        w.get_mut::<A>(e).unwrap().0 = 2;
2325        assert_eq!(
2326            *shared,
2327            A(1),
2328            "a write through the world copies the shared value first"
2329        );
2330        assert_eq!(w.get::<A>(e), Some(&A(2)));
2331        let unshared = w.get::<A>(e).unwrap() as *const A;
2332        w.get_mut::<A>(e).unwrap().0 = 3;
2333        assert_eq!(
2334            w.get::<A>(e).unwrap() as *const A,
2335            unshared,
2336            "a value nothing shares is written in place"
2337        );
2338        assert_eq!(w.get_shared::<B>(e), None);
2339    }
2340
2341    #[test]
2342    fn a_clone_of_the_world_shares_its_values_until_either_writes() {
2343        let mut w = World::new();
2344        let es: Vec<Entity> = (0..3).map(|_| w.spawn()).collect();
2345        for (i, &e) in es.iter().enumerate() {
2346            w.insert(e, A(i as u32));
2347        }
2348        let mut clone = w.clone();
2349        for &e in &es {
2350            assert!(
2351                std::ptr::eq(w.get::<A>(e).unwrap(), clone.get::<A>(e).unwrap()),
2352                "shared after the clone"
2353            );
2354        }
2355        clone.get_mut::<A>(es[0]).unwrap().0 = 10;
2356        assert_eq!(w.get::<A>(es[0]), Some(&A(0)), "the original keeps its value");
2357        assert!(!std::ptr::eq(
2358            w.get::<A>(es[0]).unwrap(),
2359            clone.get::<A>(es[0]).unwrap()
2360        ));
2361        assert!(
2362            std::ptr::eq(w.get::<A>(es[1]).unwrap(), clone.get::<A>(es[1]).unwrap()),
2363            "an unwritten value stays shared"
2364        );
2365        // every value written through a column after the clone: the original sees none of it
2366        for (_, a) in clone.column_mut::<A>().unwrap().iter_mut() {
2367            a.0 += 100;
2368        }
2369        assert_eq!(w.iter::<A>().map(|(_, a)| a.0).collect::<Vec<_>>(), [0, 1, 2]);
2370        assert_eq!(
2371            clone.iter::<A>().map(|(_, a)| a.0).collect::<Vec<_>>(),
2372            [110, 101, 102]
2373        );
2374        for (_, a) in w.column_mut::<A>().unwrap().iter_mut() {
2375            a.0 += 1;
2376        }
2377        assert_eq!(w.iter::<A>().map(|(_, a)| a.0).collect::<Vec<_>>(), [1, 2, 3]);
2378        assert_eq!(
2379            clone.iter::<A>().map(|(_, a)| a.0).collect::<Vec<_>>(),
2380            [110, 101, 102]
2381        );
2382    }
2383
2384    #[test]
2385    fn removing_or_replacing_a_shared_value_leaves_its_sharers_theirs() {
2386        let mut w = World::new();
2387        let e = w.spawn();
2388        w.insert(e, A(7));
2389        let shared = w.get_shared::<A>(e).unwrap();
2390        let clone = w.clone();
2391        assert_eq!(
2392            w.remove::<A>(e),
2393            Some(A(7)),
2394            "a shared value is taken out as a copy"
2395        );
2396        assert_eq!(*shared, A(7));
2397        assert_eq!(clone.get::<A>(e), Some(&A(7)));
2398        assert_eq!(w.get::<A>(e), None);
2399        w.insert(e, A(8));
2400        assert_eq!(
2401            w.insert(e, A(9)),
2402            Some(A(8)),
2403            "the value replaced is returned whole"
2404        );
2405        assert_eq!(clone.get::<A>(e), Some(&A(7)));
2406        // a value nothing else shares is moved out, not copied
2407        let f = w.spawn();
2408        w.insert(f, B("only"));
2409        assert_eq!(w.remove::<B>(f), Some(B("only")));
2410    }
2411
2412    #[test]
2413    fn a_value_taken_out_shared_is_the_world_s_own_never_a_copy() {
2414        let mut w = World::new();
2415        let e = w.spawn();
2416        w.insert(e, A(7));
2417        let held = w.get_shared::<A>(e).unwrap();
2418        let taken = w.remove_shared::<A>(e).unwrap();
2419        assert!(
2420            Arc::ptr_eq(&held, &taken),
2421            "taken out while shared, the handle is the world's value, not a copy"
2422        );
2423        assert_eq!(w.get::<A>(e), None);
2424        assert_eq!(w.remove_shared::<A>(e), None);
2425        drop(held);
2426        assert_eq!(
2427            Arc::into_inner(taken),
2428            Some(A(7)),
2429            "the last handle owns the value alone"
2430        );
2431        assert_eq!(w.remove_shared::<B>(e), None, "a type the world never held");
2432    }
2433
2434    #[test]
2435    fn iteration_is_in_entity_order_regardless_of_insert_order() {
2436        let mut w = World::new();
2437        let es: Vec<Entity> = (0..5).map(|_| w.spawn()).collect();
2438        for &e in es.iter().rev() {
2439            w.insert(e, A(e.index() * 10));
2440        }
2441        let got: Vec<u32> = w.iter::<A>().map(|(_, a)| a.0).collect();
2442        assert_eq!(got, [0, 10, 20, 30, 40]);
2443    }
2444
2445    /// One value per vertex of each primitive: follows primitives and vertices.
2446    #[derive(Clone, Debug, PartialEq)]
2447    struct PerVertex(Vec<Vec<u8>>);
2448    impl Component for PerVertex {
2449        const NAME: &'static str = "test.per_vertex";
2450        const GEOMETRY: crate::Geometry = crate::Geometry::PerVertex;
2451        fn remap_primitives(&self, from: &[usize]) -> Option<Result<Self, String>> {
2452            Some(remap_list(&self.0, from).map(PerVertex))
2453        }
2454        fn remap_vertices(&self, primitive: usize, from: &[u32]) -> Option<Result<Self, String>> {
2455            let mut out = self.0.clone();
2456            let Some(list) = self.0.get(primitive) else {
2457                return Some(Err(format!("primitive {primitive} of {}", self.0.len())));
2458            };
2459            out[primitive] = match from
2460                .iter()
2461                .map(|&i| {
2462                    list.get(i as usize)
2463                        .copied()
2464                        .ok_or(format!("vertex {i} of {}", list.len()))
2465                })
2466                .collect()
2467            {
2468                Ok(v) => v,
2469                Err(e) => return Some(Err(e)),
2470            };
2471            Some(Ok(PerVertex(out)))
2472        }
2473    }
2474
2475    /// States it holds something per primitive (or per vertex) but does not answer an edit: what a component that
2476    /// forgot to follow its mesh looks like to the World.
2477    #[derive(Clone, Debug, PartialEq)]
2478    struct Unanswering(crate::Geometry);
2479    impl Component for Unanswering {
2480        const NAME: &'static str = "test.unanswering";
2481        const GEOMETRY: crate::Geometry = crate::Geometry::PerVertex;
2482        fn remap_primitives(&self, _from: &[usize]) -> Option<Result<Self, String>> {
2483            (self.0 != crate::Geometry::PerPrimitive).then(|| Ok(self.clone()))
2484        }
2485        fn remap_vertices(&self, _primitive: usize, _from: &[u32]) -> Option<Result<Self, String>> {
2486            None
2487        }
2488    }
2489
2490    fn points(n: usize) -> crate::Primitive {
2491        crate::Primitive {
2492            topology: crate::Topology::Points,
2493            streams: [(crate::Semantic::Position, crate::Stream::F32x3(vec![[0.0; 3]; n]))].into(),
2494            indices: None,
2495            material: None,
2496        }
2497    }
2498
2499    /// A component stating it describes the mesh must answer the edits it describes: one that doesn't is refused,
2500    /// naming it, and nothing changes. One stating `None` is kept as it is.
2501    #[test]
2502    fn edits_refuse_a_dependent_component_that_does_not_answer() {
2503        let mut w = World::new();
2504        let e = w.spawn();
2505        w.insert(e, crate::Mesh::new(vec![points(2), points(2)]));
2506        w.insert(e, A(7));
2507        // per primitive: a rebuild of the list is refused
2508        w.insert(e, Unanswering(crate::Geometry::PerPrimitive));
2509        let err = w
2510            .rebuild_primitives(e, |m| Ok((vec![m.primitives()[1].clone()], vec![1])))
2511            .unwrap_err();
2512        assert!(
2513            err.contains("test.unanswering") && err.contains("per primitive"),
2514            "{err}"
2515        );
2516        assert_eq!(
2517            w.get::<crate::Mesh>(e).unwrap().primitives().len(),
2518            2,
2519            "nothing changed"
2520        );
2521        // per vertex: it answers the rebuild, but a compaction is refused
2522        w.insert(e, Unanswering(crate::Geometry::PerVertex));
2523        let err = w.remap_vertices(e, 0, &[1]).unwrap_err();
2524        assert!(
2525            err.contains("test.unanswering") && err.contains("per vertex"),
2526            "{err}"
2527        );
2528        // a component of Geometry::None follows nothing and is never refused
2529        w.remove::<Unanswering>(e);
2530        w.rebuild_primitives(e, |m| Ok((vec![m.primitives()[1].clone()], vec![1])))
2531            .unwrap();
2532        w.remap_vertices(e, 0, &[1]).unwrap();
2533        assert_eq!(w.get::<A>(e), Some(&A(7)));
2534    }
2535
2536    /// Moving one form onto another can't leave data describing one mesh beside another: `from` bringing a mesh
2537    /// while `to` keeps per-primitive data `from` lacks, or `from` bringing such data without a mesh onto `to`'s mesh,
2538    /// is refused, changing nothing. With `to`'s mesh taken away first it moves.
2539    #[test]
2540    fn a_move_leaving_stale_mesh_data_is_refused() {
2541        use crate::{MaterialVariants, Mesh};
2542        let mut w = World::new();
2543        let (to, from) = (w.spawn(), w.spawn());
2544        w.insert(to, Mesh::new(vec![points(1)]));
2545        w.insert(to, MaterialVariants(vec![Default::default()]));
2546        w.insert(from, Mesh::new(vec![points(3), points(3)]));
2547        let err = w.move_components(from, to).unwrap_err();
2548        assert!(err.contains("core.material_variants"), "{err}");
2549        assert!(w.is_alive(from) && w.get::<Mesh>(to).unwrap().primitives().len() == 1);
2550        // data without a mesh onto a mesh
2551        let bare = w.spawn();
2552        w.insert(bare, MaterialVariants(vec![]));
2553        let err = w.move_components(bare, to).unwrap_err();
2554        assert!(err.contains("core.material_variants"), "{err}");
2555        assert!(w.is_alive(bare));
2556        // the old geometry taken away first: the move goes through
2557        w.remove_mesh(to).unwrap();
2558        assert!(w.move_components(from, to).unwrap());
2559        assert_eq!(w.get::<Mesh>(to).unwrap().primitives().len(), 2);
2560    }
2561
2562    /// A primitive's vertices compacted: a per-vertex component follows them (after a rebuild that kept only
2563    /// primitive 1, from its source primitive's values); one that holds nothing per vertex is kept; an index the
2564    /// component lacks fails naming it, and an opaque component refuses, each changing nothing.
2565    #[test]
2566    fn per_vertex_components_follow_a_compaction() {
2567        let mut w = World::new();
2568        let e = w.spawn();
2569        w.insert(e, PerVertex(vec![vec![10, 11], vec![20, 21, 22, 23]]));
2570        w.insert(e, A(7));
2571        // keep primitive 1 only, then its vertices 3 and 1
2572        w.remap_primitives(e, &[1]).unwrap();
2573        w.remap_vertices(e, 0, &[3, 1]).unwrap();
2574        assert_eq!(w.get::<PerVertex>(e), Some(&PerVertex(vec![vec![23, 21]])));
2575        assert_eq!(w.get::<A>(e), Some(&A(7)));
2576        let err = w.remap_vertices(e, 0, &[5]).unwrap_err();
2577        assert!(
2578            err.contains("test.per_vertex") && err.contains("vertex 5 of 2"),
2579            "{err}"
2580        );
2581        assert_eq!(w.get::<PerVertex>(e), Some(&PerVertex(vec![vec![23, 21]])));
2582        w.insert_opaque(
2583            e,
2584            "game.thing",
2585            Opaque {
2586                version: 1,
2587                data: OpaqueData::Bytes(vec![1]),
2588            },
2589        )
2590        .unwrap();
2591        assert!(w.remap_vertices(e, 0, &[1]).unwrap_err().contains("game.thing"));
2592        assert_eq!(w.get::<PerVertex>(e), Some(&PerVertex(vec![vec![23, 21]])));
2593    }
2594
2595    /// `check_remap_vertices` states what `remap_vertices` would do and changes nothing.
2596    #[test]
2597    fn the_check_of_a_vertex_remap_changes_nothing() {
2598        let mut w = World::new();
2599        let e = w.spawn();
2600        w.insert(e, PerVertex(vec![vec![10, 11]]));
2601        w.check_remap_vertices(e, 0, &[1, 0, 1]).unwrap();
2602        assert_eq!(w.get::<PerVertex>(e), Some(&PerVertex(vec![vec![10, 11]])));
2603        let err = w.check_remap_vertices(e, 0, &[2]).unwrap_err();
2604        assert!(err.contains("vertex 2 of 2"), "{err}");
2605        w.insert(e, Unanswering(crate::Geometry::PerVertex));
2606        let err = w.check_remap_vertices(e, 0, &[0]).unwrap_err();
2607        assert!(err.contains("test.unanswering"), "{err}");
2608    }
2609
2610    /// A mesh taken away goes with what follows its primitives; with an opaque component (which can't be known to
2611    /// describe primitives or not) nothing changes.
2612    #[test]
2613    fn remove_mesh_takes_its_per_primitive_components_and_refuses_with_opaque_data() {
2614        use crate::{MaterialVariants, Mesh, MeshFile};
2615        let mut w = World::new();
2616        let e = w.spawn();
2617        w.insert(e, Mesh::new(Vec::new()));
2618        w.insert(e, MaterialVariants(Vec::new()));
2619        w.insert(
2620            e,
2621            MeshFile {
2622                path: "a.glb".into(),
2623                mesh: 0,
2624                materials: Vec::new(),
2625            },
2626        );
2627        w.insert(e, A(1));
2628        w.insert_opaque(
2629            e,
2630            "game.thing",
2631            Opaque {
2632                version: 1,
2633                data: OpaqueData::Bytes(vec![1]),
2634            },
2635        )
2636        .unwrap();
2637        assert!(w.remove_mesh(e).unwrap_err().contains("game.thing"));
2638        assert!(w.has::<Mesh>(e) && w.has::<MaterialVariants>(e));
2639        w.remove_opaque(e, "game.thing");
2640        assert_eq!(
2641            w.remove_mesh(e).unwrap(),
2642            ["core.mesh", "core.material_variants", "core.mesh_file"]
2643        );
2644        // nothing left to restore the mesh from
2645        assert!(!w.has::<Mesh>(e) && !w.has::<MaterialVariants>(e) && !w.has::<MeshFile>(e));
2646        // what does not follow primitives stays
2647        assert!(w.has::<A>(e));
2648        assert!(w.remove_mesh(e).unwrap().is_empty());
2649        // a mesh still only in its file goes the same way, with the per-primitive data that describes it
2650        w.insert(e, MaterialVariants(Vec::new()));
2651        w.insert(
2652            e,
2653            MeshFile {
2654                path: "a.glb".into(),
2655                mesh: 0,
2656                materials: Vec::new(),
2657            },
2658        );
2659        assert_eq!(
2660            w.remove_mesh(e).unwrap(),
2661            ["core.material_variants", "core.mesh_file"]
2662        );
2663        assert!(!w.has::<MaterialVariants>(e) && !w.has::<MeshFile>(e) && w.has::<A>(e));
2664    }
2665
2666    #[test]
2667    fn iter2_joins_and_despawn_removes_everything() {
2668        let mut w = World::new();
2669        let e0 = w.spawn();
2670        let e1 = w.spawn();
2671        w.insert(e0, A(1));
2672        w.insert(e1, A(2));
2673        w.insert(e1, B("x"));
2674        w.insert_opaque(
2675            e1,
2676            "game.thing",
2677            Opaque {
2678                version: 3,
2679                data: OpaqueData::Bytes(vec![1, 2]),
2680            },
2681        )
2682        .unwrap();
2683        assert_eq!(w.iter2::<A, B>().map(|(e, ..)| e).collect::<Vec<_>>(), [e1]);
2684        assert!(w.entity_has_named(e1, "game.thing"));
2685        assert_eq!(w.component_names(), ["game.thing", "test.a", "test.b"]);
2686        assert!(w.despawn(e1));
2687        assert!(!w.has::<A>(e1) && w.get_opaque(e1, "game.thing").is_none());
2688        assert_eq!(w.component_names(), ["test.a"]);
2689        let e2 = w.spawn();
2690        assert_ne!(e2, e1, "ids are never reused");
2691    }
2692
2693    #[test]
2694    fn columns2_mut_reads_one_writes_another() {
2695        let mut w = World::new();
2696        let e = w.spawn();
2697        w.insert(e, A(7));
2698        w.insert(e, B("a"));
2699        let (a, b) = w.columns2_mut::<A, B>();
2700        let (a, mut b) = (a.unwrap(), b.unwrap());
2701        if a.get(e).unwrap().0 == 7 {
2702            *b.get_mut(e).unwrap() = B("seven");
2703        }
2704        assert_eq!(w.get::<B>(e), Some(&B("seven")));
2705    }
2706
2707    #[test]
2708    fn move_components_replaces_by_name_and_keeps_the_rest() {
2709        let mut w = World::new();
2710        let from = w.spawn();
2711        let to = w.spawn();
2712        w.insert(from, A(9));
2713        w.insert(to, A(1));
2714        w.insert(to, B("kept"));
2715        let opaque = Opaque {
2716            version: 4,
2717            data: OpaqueData::Bytes(vec![3, 2, 1]),
2718        };
2719        w.insert_opaque(from, "game.form", opaque.clone()).unwrap();
2720        assert!(!w.move_components(from, from).unwrap());
2721        assert!(!w.move_components(from, Entity::from_index(999)).unwrap());
2722        assert_eq!(w.get::<A>(from), Some(&A(9)), "a refused move changes nothing");
2723        assert!(w.move_components(from, to).unwrap());
2724        assert!(!w.is_alive(from));
2725        assert_eq!(w.get::<A>(to), Some(&A(9)));
2726        assert_eq!(w.get::<B>(to), Some(&B("kept")));
2727        assert_eq!(w.get_opaque(to, "game.form"), Some(&opaque));
2728        assert!(!w.move_components(from, to).unwrap());
2729        assert_ne!(w.spawn(), from, "the moved-from id is not reused");
2730    }
2731
2732    #[derive(Clone, Debug, PartialEq)]
2733    struct NamedLikeA;
2734    impl Resource for NamedLikeA {
2735        const NAME: &'static str = "test.a";
2736    }
2737
2738    #[test]
2739    #[should_panic(expected = "one kind of them")]
2740    fn a_resource_cannot_take_a_component_name() {
2741        let mut w = World::new();
2742        let e = w.spawn();
2743        w.insert(e, A(1));
2744        w.insert_resource(NamedLikeA);
2745    }
2746
2747    #[test]
2748    #[should_panic(expected = "one kind of them")]
2749    fn a_component_cannot_take_a_resource_name() {
2750        let mut w = World::new();
2751        w.insert_resource(NamedLikeA);
2752        let e = w.spawn();
2753        w.insert(e, A(1));
2754    }
2755
2756    #[test]
2757    fn resource_names_list_typed_and_opaque_sorted() {
2758        let mut w = World::new();
2759        w.insert_resource(R(1));
2760        w.insert_opaque_resource(
2761            "game.settings",
2762            Opaque {
2763                version: 1,
2764                data: OpaqueData::Bytes(vec![]),
2765            },
2766        )
2767        .unwrap();
2768        assert_eq!(w.resource_names(), ["game.settings", "test.r"]);
2769    }
2770
2771    #[test]
2772    fn copy_components_replaces_by_name_keeps_the_rest_and_the_source() {
2773        let mut w = World::new();
2774        let from = w.spawn();
2775        let to = w.spawn();
2776        w.insert(from, A(9));
2777        w.insert(to, A(1));
2778        w.insert(to, B("kept"));
2779        let opaque = Opaque {
2780            version: 4,
2781            data: OpaqueData::Bytes(vec![3, 2, 1]),
2782        };
2783        w.insert_opaque(from, "game.form", opaque.clone()).unwrap();
2784        assert!(!w.copy_components(from, from));
2785        assert!(!w.copy_components(from, Entity::from_index(999)));
2786        assert!(w.copy_components(from, to));
2787        assert!(w.is_alive(from));
2788        assert_eq!(w.get::<A>(from), Some(&A(9)));
2789        assert_eq!(w.get_opaque(from, "game.form"), Some(&opaque));
2790        assert_eq!(w.get::<A>(to), Some(&A(9)));
2791        assert_eq!(w.get::<B>(to), Some(&B("kept")));
2792        assert_eq!(w.get_opaque(to, "game.form"), Some(&opaque));
2793    }
2794
2795    #[test]
2796    #[should_panic(expected = "another component type's name")]
2797    fn two_types_cannot_share_a_name() {
2798        let mut w = World::new();
2799        let e = w.spawn();
2800        w.insert(e, A(1));
2801        w.insert(e, Same);
2802    }
2803
2804    #[derive(Clone, Debug, PartialEq, serde::Serialize)]
2805    struct Shown {
2806        x: u32,
2807        of: Entity,
2808    }
2809    impl Component for Shown {
2810        const NAME: &'static str = "test.shown";
2811        const GEOMETRY: crate::Geometry = crate::Geometry::None;
2812        const VERSION: u32 = 2;
2813        fn to_json(&self) -> Result<Option<serde_json::Value>, JsonError> {
2814            crate::json::to_value(self).map(Some)
2815        }
2816    }
2817
2818    #[test]
2819    fn components_json_lists_every_component_sorted() {
2820        let mut w = World::new();
2821        let e0 = w.spawn();
2822        let e = w.spawn();
2823        w.insert(e, Shown { x: 3, of: e0 });
2824        w.insert(e, A(1));
2825        w.insert_opaque(
2826            e,
2827            "game.bytes",
2828            Opaque {
2829                version: 1,
2830                data: OpaqueData::Bytes(vec![9]),
2831            },
2832        )
2833        .unwrap();
2834        w.insert_opaque(
2835            e,
2836            "game.json",
2837            Opaque {
2838                version: 1,
2839                data: OpaqueData::Json(serde_json::json!({"k": 1})),
2840            },
2841        )
2842        .unwrap();
2843        let got: Vec<(&str, u32, Option<serde_json::Value>)> = w
2844            .components_json(e)
2845            .unwrap()
2846            .into_iter()
2847            .map(|c| (c.name, c.version, c.value))
2848            .collect();
2849        assert_eq!(
2850            got,
2851            [
2852                ("game.bytes", 1, None),
2853                ("game.json", 1, Some(serde_json::json!({"k": 1}))),
2854                ("test.a", 1, None),
2855                ("test.shown", 2, Some(serde_json::json!({"x": 3, "of": 0}))),
2856            ]
2857        );
2858        assert!(w.components_json(e0).unwrap().is_empty());
2859    }
2860
2861    #[derive(Clone, Debug, PartialEq, serde::Serialize)]
2862    struct F(f32);
2863    impl Component for F {
2864        const NAME: &'static str = "test.f";
2865        const GEOMETRY: crate::Geometry = crate::Geometry::None;
2866        fn to_json(&self) -> Result<Option<serde_json::Value>, JsonError> {
2867            crate::json::to_value(self).map(Some)
2868        }
2869    }
2870    impl Resource for F {
2871        const NAME: &'static str = "test.res";
2872        const VERSION: u32 = 4;
2873        fn to_json(&self) -> Result<Option<serde_json::Value>, JsonError> {
2874            crate::json::to_value(self).map(Some)
2875        }
2876    }
2877
2878    #[test]
2879    fn a_json_view_that_would_lose_a_value_is_an_error() {
2880        let mut w = World::new();
2881        let e = w.spawn();
2882        w.insert(e, F(f32::NAN));
2883        assert_eq!(
2884            w.components_json(e).unwrap_err().to_string(),
2885            "test.f on e0: NaN at the value: JSON has no non-finite numbers"
2886        );
2887        w.insert_resource(F(0.5));
2888        let r = w.resources_json().unwrap();
2889        assert_eq!(
2890            (r[0].name, r[0].version, r[0].value.clone()),
2891            ("test.res", 4, Some(serde_json::json!(0.5)))
2892        );
2893        w.insert_resource(F(f32::INFINITY));
2894        assert_eq!(
2895            w.resources_json().unwrap_err().to_string(),
2896            "test.res: inf at the value: JSON has no non-finite numbers"
2897        );
2898    }
2899
2900    #[derive(Clone, Debug, PartialEq)]
2901    struct Points(Entity);
2902    impl Component for Points {
2903        const NAME: &'static str = "test.points";
2904        const GEOMETRY: crate::Geometry = crate::Geometry::None;
2905        fn references(&self, out: &mut Vec<Entity>) {
2906            out.push(self.0);
2907        }
2908    }
2909
2910    #[test]
2911    fn a_reference_to_a_despawned_entity_fails_verification() {
2912        let mut w = World::new();
2913        let target = w.spawn();
2914        let holder = w.spawn();
2915        w.insert(holder, Points(target));
2916        assert!(w.verify_components().is_empty());
2917        w.despawn(target);
2918        assert_eq!(
2919            w.verify_components(),
2920            [(
2921                "test.points",
2922                holder,
2923                format!("refers to {target:?}, which is not alive")
2924            )]
2925        );
2926    }
2927
2928    #[test]
2929    #[should_panic(expected = "opaque component")]
2930    fn a_typed_component_cannot_take_an_opaque_name() {
2931        let mut w = World::new();
2932        let e = w.spawn();
2933        w.insert_opaque(
2934            e,
2935            "test.a",
2936            Opaque {
2937                version: 1,
2938                data: OpaqueData::Bytes(vec![]),
2939            },
2940        )
2941        .unwrap();
2942        w.insert(e, A(1));
2943    }
2944
2945    #[test]
2946    fn resources_and_clone() {
2947        let mut w = World::new();
2948        assert!(w.insert_resource(R(1)).is_none());
2949        assert_eq!(w.insert_resource(R(2)), Some(R(1)));
2950        let e = w.spawn();
2951        w.insert(e, A(5));
2952        let w2 = w.clone();
2953        w.get_mut::<A>(e).unwrap().0 = 6;
2954        assert_eq!(w2.get::<A>(e), Some(&A(5)));
2955        assert_eq!(w2.resource::<R>(), Some(&R(2)));
2956    }
2957
2958    fn opaque() -> Opaque {
2959        Opaque {
2960            version: 1,
2961            data: OpaqueData::Bytes(vec![]),
2962        }
2963    }
2964
2965    /// A name a typed component, an opaque component and a resource could each take is one kind's: the second to
2966    /// claim it is refused, an error, whichever came first.
2967    #[test]
2968    fn a_name_clash_is_an_error_whichever_claimed_it_first() {
2969        // typed, then opaque
2970        let mut w = World::new();
2971        let e = w.spawn();
2972        w.insert(e, A(1));
2973        let clash = w.insert_opaque(e, "test.a", opaque()).unwrap_err();
2974        assert_eq!(clash.name, "test.a");
2975        assert!(clash.held.contains("typed component"), "{clash}");
2976        assert!(w.get_opaque(e, "test.a").is_none(), "a refusal changes nothing");
2977        // opaque, then typed
2978        let mut w = World::new();
2979        let e = w.spawn();
2980        w.insert_opaque(e, "test.a", opaque()).unwrap();
2981        let clash = w.try_insert(e, A(1)).unwrap_err();
2982        assert!(clash.held.contains("opaque component"), "{clash}");
2983        assert!(!w.has::<A>(e), "a refusal changes nothing");
2984        // the same for a resource and a component
2985        let mut w = World::new();
2986        w.insert_resource(NamedLikeA);
2987        let e = w.spawn();
2988        assert!(w.try_insert(e, A(1)).unwrap_err().held.contains("resource"));
2989        assert!(
2990            w.insert_opaque(e, "test.a", opaque())
2991                .unwrap_err()
2992                .held
2993                .contains("resource")
2994        );
2995        let mut w = World::new();
2996        let e = w.spawn();
2997        w.insert(e, A(1));
2998        assert!(
2999            w.try_insert_resource(NamedLikeA)
3000                .unwrap_err()
3001                .held
3002                .contains("component")
3003        );
3004        assert!(
3005            w.insert_opaque_resource("test.a", opaque())
3006                .unwrap_err()
3007                .held
3008                .contains("component")
3009        );
3010        // two types for one name
3011        assert!(
3012            w.try_insert(e, Same)
3013                .unwrap_err()
3014                .held
3015                .contains("another component type")
3016        );
3017        // a free name is taken
3018        assert_eq!(w.try_insert(e, B("x")).unwrap(), None);
3019    }
3020
3021    /// Ids from a file: ascending, with gaps; one at or below one already used, or the last id, is an error.
3022    #[test]
3023    fn an_id_from_a_file_is_an_error_not_a_panic() {
3024        let mut w = World::new();
3025        assert_eq!(w.spawn_at(Entity::from_index(5)), Ok(Entity::from_index(5)));
3026        assert_eq!(w.spawn(), Entity::from_index(6));
3027        assert_eq!(
3028            w.spawn_at(Entity::from_index(6)),
3029            Err(IdError::NotAscending(Entity::from_index(6)))
3030        );
3031        assert_eq!(
3032            w.spawn_at(Entity::from_index(2)),
3033            Err(IdError::NotAscending(Entity::from_index(2)))
3034        );
3035        assert_eq!(w.entity_count(), 2, "a refusal changes nothing");
3036        let last = Entity::from_index(u32::MAX);
3037        assert_eq!(w.spawn_at(last), Err(IdError::Exhausted(last)));
3038        assert!(!w.is_alive(last));
3039        assert_eq!(w.spawn(), Entity::from_index(7));
3040    }
3041
3042    #[test]
3043    fn reserving_indices_for_a_reloaded_part_never_rewinds_or_spawns_entities() {
3044        let mut world = World::new();
3045        let first = world.spawn();
3046        world.reserve_indices_before(100);
3047        assert_eq!(world.entity_count(), 1);
3048        assert!(world.is_alive(first));
3049        assert_eq!(world.spawn().index(), 100);
3050        world.reserve_indices_before(5);
3051        assert_eq!(world.spawn().index(), 101);
3052    }
3053
3054    /// A part with an entity alive in the world it is absorbed into is an error that changes nothing.
3055    #[test]
3056    fn absorbing_a_part_that_overlaps_is_an_error() {
3057        let mut w = World::new();
3058        let e = w.spawn();
3059        w.insert(e, A(1));
3060        let part = w.clone();
3061        let before = format!("{w:?}");
3062        assert_eq!(w.absorb(part), Err(IdError::Alive(e)));
3063        assert_eq!(format!("{w:?}"), before);
3064    }
3065
3066    /// A resource that keeps a reference it was told to forget breaks its contract: caught in release when a whole
3067    /// selection leaves, not only in debug builds.
3068    #[derive(Clone, Debug, PartialEq)]
3069    struct Stubborn(Entity);
3070    impl Resource for Stubborn {
3071        const NAME: &'static str = "test.stubborn";
3072        fn references(&self, out: &mut Vec<Entity>) {
3073            out.push(self.0);
3074        }
3075    }
3076
3077    #[test]
3078    #[should_panic(expected = "keeps a reference")]
3079    fn a_resource_that_keeps_a_reference_is_refused_when_a_selection_leaves() {
3080        let mut w = World::new();
3081        let (a, b) = (w.spawn(), w.spawn());
3082        w.insert_resource(Stubborn(b));
3083        w.retain(&BTreeSet::from([a]));
3084    }
3085}