polyscope_core/
registry.rs1use std::collections::HashMap;
4
5use crate::error::{PolyscopeError, Result};
6use crate::structure::Structure;
7
8#[derive(Default)]
12pub struct Registry {
13 structures: HashMap<String, HashMap<String, Box<dyn Structure>>>,
15}
16
17impl Registry {
18 #[must_use]
20 pub fn new() -> Self {
21 Self::default()
22 }
23
24 pub fn register(&mut self, structure: Box<dyn Structure>) -> Result<()> {
28 let type_name = structure.type_name().to_string();
29 let name = structure.name().to_string();
30
31 let type_map = self.structures.entry(type_name).or_default();
32
33 if type_map.contains_key(&name) {
34 return Err(PolyscopeError::StructureExists(name));
35 }
36
37 type_map.insert(name, structure);
38 Ok(())
39 }
40
41 #[must_use]
43 pub fn get(&self, type_name: &str, name: &str) -> Option<&dyn Structure> {
44 self.structures
45 .get(type_name)
46 .and_then(|m| m.get(name))
47 .map(std::convert::AsRef::as_ref)
48 }
49
50 pub fn get_mut(&mut self, type_name: &str, name: &str) -> Option<&mut Box<dyn Structure>> {
52 self.structures.get_mut(type_name)?.get_mut(name)
53 }
54
55 #[must_use]
57 pub fn contains(&self, type_name: &str, name: &str) -> bool {
58 self.structures
59 .get(type_name)
60 .is_some_and(|m| m.contains_key(name))
61 }
62
63 pub fn remove(&mut self, type_name: &str, name: &str) -> Option<Box<dyn Structure>> {
65 self.structures
66 .get_mut(type_name)
67 .and_then(|m| m.remove(name))
68 }
69
70 pub fn remove_all_of_type(&mut self, type_name: &str) {
72 self.structures.remove(type_name);
73 }
74
75 pub fn clear(&mut self) {
77 self.structures.clear();
78 }
79
80 pub fn iter(&self) -> impl Iterator<Item = &dyn Structure> {
82 self.structures
83 .values()
84 .flat_map(|m| m.values())
85 .map(std::convert::AsRef::as_ref)
86 }
87
88 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Box<dyn Structure>> + '_ {
90 self.structures.values_mut().flat_map(|m| m.values_mut())
91 }
92
93 #[must_use]
95 pub fn len(&self) -> usize {
96 self.structures
97 .values()
98 .map(std::collections::HashMap::len)
99 .sum()
100 }
101
102 #[must_use]
104 pub fn is_empty(&self) -> bool {
105 self.structures
106 .values()
107 .all(std::collections::HashMap::is_empty)
108 }
109
110 pub fn get_all_of_type(&self, type_name: &str) -> impl Iterator<Item = &dyn Structure> {
112 self.structures
113 .get(type_name)
114 .into_iter()
115 .flat_map(|m| m.values())
116 .map(std::convert::AsRef::as_ref)
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use std::any::Any;
123
124 use super::*;
125 use crate::pick::PickResult;
126 use glam::{Mat4, Vec3};
127
128 struct MockStructure {
130 name: String,
131 type_name: &'static str,
132 enabled: bool,
133 transform: Mat4,
134 }
135
136 impl MockStructure {
137 fn new(name: &str, type_name: &'static str) -> Self {
138 Self {
139 name: name.to_string(),
140 type_name,
141 enabled: true,
142 transform: Mat4::IDENTITY,
143 }
144 }
145 }
146
147 impl Structure for MockStructure {
148 fn as_any(&self) -> &dyn Any {
149 self
150 }
151 fn as_any_mut(&mut self) -> &mut dyn Any {
152 self
153 }
154 fn name(&self) -> &str {
155 &self.name
156 }
157 fn type_name(&self) -> &'static str {
158 self.type_name
159 }
160 fn bounding_box(&self) -> Option<(Vec3, Vec3)> {
161 None
162 }
163 fn length_scale(&self) -> f32 {
164 1.0
165 }
166 fn transform(&self) -> Mat4 {
167 self.transform
168 }
169 fn set_transform(&mut self, transform: Mat4) {
170 self.transform = transform;
171 }
172 fn is_enabled(&self) -> bool {
173 self.enabled
174 }
175 fn set_enabled(&mut self, enabled: bool) {
176 self.enabled = enabled;
177 }
178 fn draw(&self, _ctx: &mut dyn crate::structure::RenderContext) {}
179 fn draw_pick(&self, _ctx: &mut dyn crate::structure::RenderContext) {}
180 fn build_ui(&mut self, _ui: &dyn Any) {}
181 fn build_pick_ui(&self, _ui: &dyn Any, _pick: &PickResult) {}
182 fn refresh(&mut self) {}
183 }
184
185 fn mock(name: &str, type_name: &'static str) -> Box<dyn Structure> {
186 Box::new(MockStructure::new(name, type_name))
187 }
188
189 #[test]
190 fn test_new_registry_is_empty() {
191 let reg = Registry::new();
192 assert!(reg.is_empty());
193 assert_eq!(reg.len(), 0);
194 }
195
196 #[test]
197 fn test_register_and_get() {
198 let mut reg = Registry::new();
199 reg.register(mock("bunny", "SurfaceMesh")).unwrap();
200
201 assert!(!reg.is_empty());
202 assert_eq!(reg.len(), 1);
203 assert!(reg.contains("SurfaceMesh", "bunny"));
204
205 let s = reg.get("SurfaceMesh", "bunny").unwrap();
206 assert_eq!(s.name(), "bunny");
207 assert_eq!(s.type_name(), "SurfaceMesh");
208 }
209
210 #[test]
211 fn test_register_duplicate_errors() {
212 let mut reg = Registry::new();
213 reg.register(mock("bunny", "SurfaceMesh")).unwrap();
214
215 let result = reg.register(mock("bunny", "SurfaceMesh"));
216 assert!(result.is_err());
217 }
218
219 #[test]
220 fn test_same_name_different_types() {
221 let mut reg = Registry::new();
222 reg.register(mock("data", "SurfaceMesh")).unwrap();
223 reg.register(mock("data", "PointCloud")).unwrap();
224
225 assert_eq!(reg.len(), 2);
226 assert!(reg.contains("SurfaceMesh", "data"));
227 assert!(reg.contains("PointCloud", "data"));
228 }
229
230 #[test]
231 fn test_get_nonexistent() {
232 let reg = Registry::new();
233 assert!(reg.get("SurfaceMesh", "bunny").is_none());
234 assert!(!reg.contains("SurfaceMesh", "bunny"));
235 }
236
237 #[test]
238 fn test_get_mut() {
239 let mut reg = Registry::new();
240 reg.register(mock("bunny", "SurfaceMesh")).unwrap();
241
242 let s = reg.get_mut("SurfaceMesh", "bunny").unwrap();
243 s.set_enabled(false);
244
245 let s = reg.get("SurfaceMesh", "bunny").unwrap();
246 assert!(!s.is_enabled());
247 }
248
249 #[test]
250 fn test_remove() {
251 let mut reg = Registry::new();
252 reg.register(mock("bunny", "SurfaceMesh")).unwrap();
253
254 let removed = reg.remove("SurfaceMesh", "bunny");
255 assert!(removed.is_some());
256 assert_eq!(removed.unwrap().name(), "bunny");
257 assert!(reg.get("SurfaceMesh", "bunny").is_none());
258 }
259
260 #[test]
261 fn test_remove_nonexistent() {
262 let mut reg = Registry::new();
263 assert!(reg.remove("SurfaceMesh", "bunny").is_none());
264 }
265
266 #[test]
267 fn test_remove_all_of_type() {
268 let mut reg = Registry::new();
269 reg.register(mock("a", "SurfaceMesh")).unwrap();
270 reg.register(mock("b", "SurfaceMesh")).unwrap();
271 reg.register(mock("c", "PointCloud")).unwrap();
272
273 reg.remove_all_of_type("SurfaceMesh");
274 assert_eq!(reg.len(), 1);
275 assert!(!reg.contains("SurfaceMesh", "a"));
276 assert!(reg.contains("PointCloud", "c"));
277 }
278
279 #[test]
280 fn test_clear() {
281 let mut reg = Registry::new();
282 reg.register(mock("a", "SurfaceMesh")).unwrap();
283 reg.register(mock("b", "PointCloud")).unwrap();
284
285 reg.clear();
286 assert!(reg.is_empty());
287 assert_eq!(reg.len(), 0);
288 }
289
290 #[test]
291 fn test_iter() {
292 let mut reg = Registry::new();
293 reg.register(mock("a", "SurfaceMesh")).unwrap();
294 reg.register(mock("b", "PointCloud")).unwrap();
295 reg.register(mock("c", "SurfaceMesh")).unwrap();
296
297 let names: Vec<&str> = reg
298 .iter()
299 .map(super::super::structure::Structure::name)
300 .collect();
301 assert_eq!(names.len(), 3);
302 assert!(names.contains(&"a"));
303 assert!(names.contains(&"b"));
304 assert!(names.contains(&"c"));
305 }
306
307 #[test]
308 fn test_get_all_of_type() {
309 let mut reg = Registry::new();
310 reg.register(mock("a", "SurfaceMesh")).unwrap();
311 reg.register(mock("b", "SurfaceMesh")).unwrap();
312 reg.register(mock("c", "PointCloud")).unwrap();
313
314 let meshes: Vec<&str> = reg
315 .get_all_of_type("SurfaceMesh")
316 .map(|s| s.name())
317 .collect();
318 assert_eq!(meshes.len(), 2);
319 assert!(meshes.contains(&"a"));
320 assert!(meshes.contains(&"b"));
321 }
322
323 #[test]
324 fn test_get_all_of_type_empty() {
325 let reg = Registry::new();
326 assert_eq!(reg.get_all_of_type("SurfaceMesh").count(), 0);
327 }
328}