arcs/systems/
name_table_bookkeeping.rs1use crate::components::{Name, NameTable};
2use specs::prelude::*;
3
4#[derive(Debug)]
6pub struct NameTableBookkeeping {
7 changes: ReaderId<ComponentEvent>,
8 inserted: BitSet,
9}
10
11impl NameTableBookkeeping {
12 pub const NAME: &'static str = module_path!();
13
14 pub fn new(world: &World) -> Self {
15 NameTableBookkeeping {
16 changes: world.write_storage::<Name>().register_reader(),
17 inserted: BitSet::new(),
18 }
19 }
20}
21
22impl<'world> System<'world> for NameTableBookkeeping {
23 type SystemData = (
24 Entities<'world>,
25 ReadStorage<'world, Name>,
26 Write<'world, NameTable>,
27 );
28
29 fn run(&mut self, data: Self::SystemData) {
30 let (entities, names, mut name_table) = data;
31
32 self.inserted.clear();
34
35 for event in names.channel().read(&mut self.changes) {
37 match dbg!(event) {
38 ComponentEvent::Inserted(id) => {
39 self.inserted.add(*id);
40 },
41 ComponentEvent::Removed(id) => {
42 name_table.remove_by_id(*id);
43 },
44 ComponentEvent::Modified(id) => {
45 name_table.remove_by_id(*id);
46 self.inserted.add(*id);
47 },
48 }
49 }
50
51 for (ent, name, _) in (&entities, &names, &self.inserted).join() {
52 use std::collections::hash_map::Entry;
53
54 match name_table.names.entry(name.clone()) {
55 Entry::Vacant(entry) => {
56 entry.insert(ent);
57 },
58 Entry::Occupied(mut entry) => {
59 log::warn!(
60 "Duplicate name found when associating {:?} with \"{}\" (previous entity: {:?})",
61 ent,
62 name.as_ref(),
63 entry.get()
64 );
65 entry.insert(ent);
66 },
67 }
68 }
69 }
70
71 fn setup(&mut self, world: &mut World) {
72 <Self::SystemData as shred::DynamicSystemData>::setup(
73 &self.accessor(),
74 world,
75 );
76
77 let entities = world.entities();
78 let names = world.read_storage::<Name>();
79 let mut name_table = world.write_resource::<NameTable>();
80
81 name_table.clear();
82
83 for (ent, name) in (&entities, &names).join() {
84 name_table.names.insert(name.clone(), ent);
85 }
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn setup_creates_all_outstanding_names() {
95 let mut world = World::new();
96 crate::components::register(&mut world);
97 let first = world.create_entity().with(Name::new("first")).build();
98 let second = world.create_entity().with(Name::new("second")).build();
99 let mut system = NameTableBookkeeping::new(&world);
100
101 System::setup(&mut system, &mut world);
102
103 let names = world.read_resource::<NameTable>();
104 assert_eq!(names.len(), 2);
105 assert_eq!(names.get("first").unwrap(), first);
106 assert_eq!(names.get("second").unwrap(), second);
107 }
108
109 #[test]
110 fn run_will_keep_the_nametable_updated() {
111 let mut world = World::new();
112 crate::components::register(&mut world);
113 let first = world.create_entity().with(Name::new("first")).build();
114 let second = world.create_entity().with(Name::new("second")).build();
115 let mut system = NameTableBookkeeping::new(&world);
116 System::setup(&mut system, &mut world);
117
118 let third = world.create_entity().with(Name::new("third")).build();
120 world.delete_entity(first).unwrap();
121 world.maintain();
122
123 system.run_now(&world);
125
126 let names = world.read_resource::<NameTable>();
127 println!("{:?}", *names);
128 assert_eq!(names.len(), 2);
129 assert!(names.get("first").is_none());
130 assert_eq!(names.get("second").unwrap(), second);
131 assert_eq!(names.get("third").unwrap(), third);
132 }
133}