1use std::any::{Any, TypeId};
8use std::collections::{BTreeMap, BTreeSet};
9use std::fmt;
10use std::sync::Arc;
11
12use crate::json::JsonError;
13
14#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct Entity(u32);
18
19impl Entity {
20 pub fn index(self) -> u32 {
22 self.0
23 }
24
25 pub fn from_index(index: u32) -> Self {
27 Entity(index)
28 }
29}
30
31impl 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
38impl<'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#[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 pub held: &'static str,
86}
87
88#[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
99pub trait Component: Any + Clone + fmt::Debug + Send + Sync {
102 const NAME: &'static str;
103 const VERSION: u32 = 1;
105 const GEOMETRY: Geometry;
109
110 fn to_json(&self) -> Result<Option<serde_json::Value>, JsonError> {
115 Ok(None)
116 }
117
118 fn verify(&self, _e: Entity, _w: &World) -> Result<(), String> {
123 Ok(())
124 }
125
126 fn references(&self, _out: &mut Vec<Entity>) {}
129
130 fn payload_bytes(&self) -> u64 {
133 0
134 }
135
136 fn remap_primitives(&self, _from: &[usize]) -> Option<Result<Self, String>> {
144 None
145 }
146
147 fn remap_vertices(&self, _primitive: usize, _from: &[u32]) -> Option<Result<Self, String>> {
156 None
157 }
158
159 fn blend_vertices(&self, _primitive: usize, _from: &[VertexBlend]) -> Option<Result<Self, String>> {
168 None
169 }
170
171 fn apply_linear(&self, _l: &crate::Linear) -> Linearity<Self> {
177 Linearity::Unsupported
178 }
179
180 fn restate(&self, _resolved: &crate::state::Resolved<'_>) -> Restated<Self> {
187 Restated::Unchanged
188 }
189}
190
191#[derive(Clone, Debug, PartialEq)]
193pub enum Restated<T> {
194 Unchanged,
196 Replaced(T),
198 Absent,
200}
201
202#[derive(Clone, Copy, Debug, PartialEq, Eq)]
206pub enum Geometry {
207 None,
209 PerPrimitive,
213 PerVertex,
216}
217
218impl Geometry {
219 pub fn describes_mesh(self) -> bool {
221 self != Geometry::None
222 }
223}
224
225#[derive(Clone, Debug, PartialEq)]
228pub enum Linearity<T> {
229 Invariant,
231 Applied(T),
233 Drop,
235 Unsupported,
237}
238
239pub 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#[derive(Clone, Copy, Debug, PartialEq)]
254pub struct VertexBlend {
255 pub sources: [u32; 3],
256 pub weights: [f32; 3],
257}
258
259impl VertexBlend {
260 pub fn copy(v: u32) -> VertexBlend {
262 VertexBlend {
263 sources: [v; 3],
264 weights: [1.0, 0.0, 0.0],
265 }
266 }
267
268 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
278type Blended = (TypeId, Box<dyn Any + Send>);
280
281pub trait Resource: Any + Clone + fmt::Debug + Send + Sync {
283 const NAME: &'static str;
284 const VERSION: u32 = 1;
285
286 fn to_json(&self) -> Result<Option<serde_json::Value>, JsonError> {
288 Ok(None)
289 }
290
291 fn verify(&self, _w: &World) -> Result<(), String> {
293 Ok(())
294 }
295
296 fn references(&self, _out: &mut Vec<Entity>) {}
299
300 fn retain_references(&mut self, _keep: &dyn Fn(Entity) -> bool) {}
304}
305
306#[derive(Clone, Debug, PartialEq)]
308pub struct ComponentJson<'w> {
309 pub name: &'w str,
310 pub version: u32,
311 pub value: Option<serde_json::Value>,
313}
314
315#[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 pub entity: Option<Entity>,
322 pub message: String,
323}
324
325#[derive(Clone, Debug, PartialEq)]
327pub enum OpaqueData {
328 Json(serde_json::Value),
329 Bytes(Vec<u8>),
330}
331
332#[derive(Clone, Debug, PartialEq)]
334pub struct Opaque {
335 pub version: u32,
336 pub data: OpaqueData,
337}
338
339#[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 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 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 fn remove_shared(&mut self, e: Entity) -> Option<Arc<T>> {
389 self.values.remove(&e)
390 }
391}
392
393impl<T: Clone> Column<T> {
394 pub fn get_mut(&mut self, e: Entity) -> Option<&mut T> {
396 self.values.get_mut(&e).map(Arc::make_mut)
397 }
398
399 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 fn remove(&mut self, e: Entity) -> Option<T> {
410 self.remove_shared(e).map(Arc::unwrap_or_clone)
411 }
412}
413
414trait 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 fn json(&self, e: Entity) -> Option<Result<Option<serde_json::Value>, JsonError>>;
424 fn verify(&self, w: &World) -> Vec<(Entity, String)>;
427 fn visit_debug(&self, f: &mut dyn FnMut(Entity, &dyn fmt::Debug));
429 fn entities(&self) -> Vec<Entity>;
430 fn references(&self, e: Entity, out: &mut Vec<Entity>);
432 fn payload_bytes(&self) -> u64;
434 fn clone_box(&self) -> Box<dyn AnyColumn>;
435 fn subset_box(&self, keep: &BTreeSet<Entity>) -> Box<dyn AnyColumn>;
437 fn retain(&mut self, keep: &BTreeSet<Entity>);
439 fn split_off_box(&mut self, keep: &BTreeSet<Entity>) -> Box<dyn AnyColumn>;
441 fn absorb(&mut self, other: Box<dyn AnyColumn>);
443 fn move_entity(&mut self, from: Entity, to: Entity);
445 fn remapped(&self, e: Entity, from: &[usize]) -> Option<Result<Box<dyn Any + Send>, String>>;
448 fn vertices_remapped(
451 &self,
452 e: Entity,
453 primitive: usize,
454 from: &[u32],
455 ) -> Option<Result<Box<dyn Any + Send>, String>>;
456 fn vertices_blended(
459 &self,
460 e: Entity,
461 primitive: usize,
462 from: &[VertexBlend],
463 ) -> Option<Result<Box<dyn Any + Send>, String>>;
464 fn put_remapped(&mut self, e: Entity, value: Box<dyn Any + Send>);
467 fn copy_entity(&mut self, from: Entity, to: Entity);
469 fn linear(&self, e: Entity, l: &crate::Linear) -> Option<Linearity<Box<dyn Any + Send>>>;
471 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
621fn 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 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#[derive(Default)]
689pub struct World {
690 next: u32,
691 alive: std::collections::BTreeSet<Entity>,
693 columns: BTreeMap<TypeId, Box<dyn AnyColumn>>,
694 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 rebuilds: Option<RebuildLog>,
703 effects: Option<Effects>,
706 dropped: Dropped,
710}
711
712#[derive(Clone, Debug, Default, PartialEq, Eq)]
717pub struct Dropped {
718 pub graph: crate::render_graph::StepsDropped,
719 pub step_bindings: Vec<(Entity, String)>,
721 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#[derive(Debug)]
773pub struct Part {
774 pub world: World,
775 pub dropped: Dropped,
776}
777
778#[derive(Clone, Debug, Default)]
780pub(crate) struct Effects {
781 pub(crate) resources_written: BTreeSet<String>,
783 pub(crate) resources_removed: BTreeSet<String>,
786 pub(crate) copies: Vec<(Entity, Entity)>,
789 pub(crate) dropped: Dropped,
792}
793
794pub(crate) type RebuildLog = BTreeMap<Entity, Option<Rebuilt>>;
797
798#[derive(Clone, Debug)]
800pub(crate) struct Rebuilt {
801 pub(crate) source: u64,
803 pub(crate) first: usize,
804 pub(crate) from: Vec<usize>,
806 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 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 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 pub fn take_dropped(&mut self) -> Dropped {
894 std::mem::take(&mut self.dropped)
895 }
896
897 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 pub(crate) fn start_effects(&mut self) {
1458 self.effects = Some(Effects::default());
1459 }
1460
1461 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 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 pub fn next_index(&self) -> u32 {
1495 self.next
1496 }
1497
1498 pub fn reserve_indices_before(&mut self, next: u32) {
1502 self.next = self.next.max(next);
1503 }
1504
1505 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 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 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 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 #[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 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 #[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 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 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 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 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 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 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 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 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 pub fn get_shared<T: Component>(&self, e: Entity) -> Option<Arc<T>> {
1797 self.column::<T>()?.get_shared(e)
1798 }
1799
1800 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 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 pub fn column_mut<T: Component>(&mut self) -> Option<ColumnMut<'_, T>> {
1830 self.column_mut_existing::<T>().map(ColumnMut)
1831 }
1832
1833 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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#[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 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 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 #[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 #[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 #[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 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 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 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 #[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 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 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 #[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 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 #[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 #[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 assert!(!w.has::<Mesh>(e) && !w.has::<MaterialVariants>(e) && !w.has::<MeshFile>(e));
2646 assert!(w.has::<A>(e));
2648 assert!(w.remove_mesh(e).unwrap().is_empty());
2649 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 #[test]
2968 fn a_name_clash_is_an_error_whichever_claimed_it_first() {
2969 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 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 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 assert!(
3012 w.try_insert(e, Same)
3013 .unwrap_err()
3014 .held
3015 .contains("another component type")
3016 );
3017 assert_eq!(w.try_insert(e, B("x")).unwrap(), None);
3019 }
3020
3021 #[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 #[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 #[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}