1use super::blueprint::{Blueprint, ComponentValue, Entity, Region};
4use comfy_table::{modifiers::UTF8_ROUND_CORNERS, presets::UTF8_FULL, Table, *};
5use std::fmt::Display;
6
7impl Display for Blueprint {
9 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 let world_table = get_world_table_display(self);
16
17 let mut region_tables: Vec<Table> = Vec::new();
19 for region in self.regions.keys() {
20 let table = get_region_table_display(region, self);
21 region_tables.push(table);
22 }
23
24 let mut entity_tables: Vec<Table> = Vec::new();
26 for entity in self.entities.keys() {
27 let table = get_entity_table_display(entity, self);
28 entity_tables.push(table);
29 }
30
31 let mut instances_table: Vec<Table> = Vec::new();
33 for region in self.regions.keys() {
34 if let Some(entities_in_region) = self.instances.get(region) {
35 for entity in entities_in_region.keys() {
36 let table = get_instances_table_display(region, entity, self);
37 instances_table.push(table);
38 }
39 }
40 }
41
42 let region_tables_string = region_tables
44 .iter()
45 .map(|t| format!("{t}"))
46 .collect::<Vec<_>>()
47 .join("\n\n");
48
49 let entity_tables_string = entity_tables
51 .iter()
52 .map(|t| format!("{t}"))
53 .collect::<Vec<_>>()
54 .join("\n\n");
55
56 let instances_table_string = instances_table
58 .iter()
59 .map(|t| format!("{t}"))
60 .collect::<Vec<_>>()
61 .join("\n\n");
62
63 write!(
64 f,
65 "{world_table}\n\n{region_tables_string}\n\n{entity_tables_string}\n\n{instances_table_string}"
66 )
67 }
68}
69
70pub fn get_world_table_display(blueprint: &Blueprint) -> Table {
77 let mut world_table = Table::new();
79
80 let mut instances_count = 0;
82 for region in blueprint.regions.keys() {
83 for entity in blueprint.entities.keys() {
84 if !blueprint.instances.contains_key(region) {
86 break;
87 }
88
89 let regional = blueprint.instances.get(region).unwrap();
91 if !regional.contains_key(entity) {
93 continue;
94 }
95
96 let instances = regional.get(entity).unwrap();
98 let count = instances.iter().filter(|_| true).count();
99 instances_count += count;
101 }
102 }
103
104 world_table
105 .load_preset(UTF8_FULL)
106 .apply_modifier(UTF8_ROUND_CORNERS)
107 .set_header(vec![
108 Cell::new("World")
109 .fg(Color::Green)
110 .add_attribute(Attribute::Bold),
111 Cell::new(&blueprint.name),
112 ])
113 .add_row(vec![
114 Cell::new("Regions").add_attribute(Attribute::Bold),
115 Cell::new(blueprint.regions.keys().filter(|_| true).count()),
116 ])
117 .add_row(vec![
118 Cell::new("Entities").add_attribute(Attribute::Bold),
119 Cell::new(blueprint.entities.keys().filter(|_| true).count()),
120 ])
121 .add_row(vec![
122 Cell::new("Instances").add_attribute(Attribute::Bold),
123 Cell::new(instances_count),
124 ]);
125
126 world_table
127}
128
129pub fn get_region_table_display(region: &Region, blueprint: &Blueprint) -> Table {
136 let mut regional_table = Table::new();
138 regional_table
139 .load_preset(UTF8_FULL)
140 .apply_modifier(UTF8_ROUND_CORNERS)
141 .set_header(vec![
142 Cell::new("Region")
143 .fg(Color::Green)
144 .add_attribute(Attribute::Bold),
145 Cell::new(region),
146 ]);
147
148 if let Some(entities) = blueprint.regions.get(region) {
149 regional_table.add_row(vec![
150 Cell::new("Entities").add_attribute(Attribute::Bold),
151 Cell::new(entities.join(", ")),
152 ]);
153 }
154
155 regional_table
156}
157
158pub fn get_entity_table_display(entity: &Entity, blueprint: &Blueprint) -> Table {
165 let mut entity_table = Table::new();
167 entity_table
168 .load_preset(UTF8_FULL)
169 .apply_modifier(UTF8_ROUND_CORNERS)
170 .set_header(vec![
171 Cell::new("Entity")
172 .fg(Color::Green)
173 .add_attribute(Attribute::Bold),
174 Cell::new(entity),
175 ]);
176
177 if let Some(component_tree) = blueprint.entities.get(entity) {
178 for (k, v) in component_tree {
179 entity_table.add_row(vec![
180 Cell::new(k).add_attribute(Attribute::Bold),
181 Cell::new(v),
182 ]);
183 }
184 }
185
186 entity_table
187}
188
189pub fn get_instances_table_display(
196 region: &Region,
197 entity: &Entity,
198 blueprint: &Blueprint,
199) -> Table {
200 let mut instances_table = Table::new();
202 instances_table
203 .load_preset(UTF8_FULL)
204 .apply_modifier(UTF8_ROUND_CORNERS)
205 .set_header(vec![
206 Cell::new("Instances")
207 .fg(Color::Green)
208 .add_attribute(Attribute::Bold),
209 Cell::new(format!("{region}, {entity}")),
210 ]);
211
212 if let Some(entities_in_region) = blueprint.instances.get(region) {
217 if let Some(instances) = entities_in_region.get(entity) {
219 for (idx, instance) in instances.iter().enumerate() {
220 let mut instance_string_pairs: Vec<String> = Vec::new();
222 for (k, c_value) in instance {
224 let value_string = match c_value {
225 ComponentValue::String(v) => v.to_string(), ComponentValue::Integer(v) => format!("{v}"),
227 ComponentValue::Float(v) => format!("{v}"),
228 ComponentValue::Boolean(v) => format!("{v}"),
229 };
230 instance_string_pairs.push(format!("{k} = {value_string}"));
231 }
232 instances_table.add_row(vec![
234 Cell::new(idx).add_attribute(Attribute::Bold),
235 Cell::new(instance_string_pairs.join(", ")),
237 ]);
238 }
239 }
240 }
241
242 instances_table
243}
244
245#[cfg(test)]
246mod tests {
247 use crate::blueprint::{Blueprint, ComponentTree, ComponentTypeTree, ComponentValue};
248 use std::collections::btree_map::BTreeMap;
249
250 #[test]
252 fn test_blueprint_display() {
253 let mut blueprint = Blueprint::new(
254 "Test World".to_string(),
255 "Test World description".to_string(),
256 );
257
258 let region1 = String::from("region1");
259 let region2 = String::from("region2");
260 let entity1 = String::from("entity1");
261 let entity2 = String::from("entity2");
262
263 blueprint.add_region(region1.clone(), vec![entity1.clone()]);
265 blueprint.add_region(region2.clone(), vec![entity2.clone()]);
266 let mut component_type_tree1: ComponentTypeTree = BTreeMap::new();
268 component_type_tree1.insert("x".to_string(), "int".to_string());
269 component_type_tree1.insert("y".to_string(), "int".to_string());
270 blueprint.add_entity(entity1.clone(), component_type_tree1);
271 let mut component_type_tree2: ComponentTypeTree = BTreeMap::new();
273 component_type_tree2.insert("w".to_string(), "float".to_string());
274 component_type_tree2.insert("h".to_string(), "float".to_string());
275 blueprint.add_entity(entity2.clone(), component_type_tree2);
276 let mut component_tree1: ComponentTree = BTreeMap::new();
278 component_tree1.insert("x".to_string(), ComponentValue::Integer(143));
279 component_tree1.insert("y".to_string(), ComponentValue::Integer(143));
280 blueprint
281 .add_instance(region1.clone(), entity1.clone(), component_tree1)
282 .unwrap();
283 let mut component_tree2: ComponentTree = BTreeMap::new();
285 component_tree2.insert("w".to_string(), ComponentValue::Float(143.0));
286 component_tree2.insert("h".to_string(), ComponentValue::Float(143.0));
287 blueprint
288 .add_instance(region2, entity2, component_tree2)
289 .unwrap();
290
291 println!("{blueprint}");
292 }
293}