1use crate::MapError;
3use std::any::{Any, TypeId};
4use std::collections::HashMap;
5use std::fmt::Debug;
6use std::hash::Hash;
7use std::sync::{Arc, Mutex};
8
9pub(crate) struct TypeMapValue {
10 concrete_type_id: TypeId,
11 trait_type_id: TypeId,
12 concrete_value: Box<dyn Any + Send + Sync>,
13 trait_object: Box<dyn Any + Send + Sync>,
14}
15
16pub struct TraitTypeMap<K> {
53 items: Arc<Mutex<HashMap<K, TypeMapValue>>>,
54}
55
56impl<K> TraitTypeMap<K>
57where
58 K: Clone + Eq + Hash + Debug,
59{
60 pub fn new() -> Self {
62 Self {
63 items: Arc::new(Mutex::new(HashMap::new())),
64 }
65 }
66
67 pub fn set_trait<T, U>(&self, key: K, value: U) -> Result<(), MapError>
81 where
82 T: ?Sized + Any + Send + Sync + 'static,
83 U: 'static + Into<Box<T>> + Send + Sync + Clone,
84 {
85 let type_map_value = TypeMapValue {
86 concrete_type_id: TypeId::of::<U>(),
87 trait_type_id: TypeId::of::<T>(),
88 concrete_value: Box::new(value.clone()),
89 trait_object: Box::new(value.into()),
90 };
91
92 let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
93 store.insert(key, type_map_value);
94 Ok(())
95 }
96
97 pub fn with<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, MapError>
105 where
106 F: FnOnce(&V) -> R,
107 {
108 let guard = self.items.lock().map_err(|_| MapError::LockError)?;
109 let value = guard
110 .get(key)
111 .ok_or_else(|| MapError::KeyNotFound(format!("{:?}", key)))?;
112
113 if value.concrete_type_id == TypeId::of::<V>() {
114 if let Some(concrete) = value.concrete_value.downcast_ref::<V>() {
115 return Ok(f(concrete));
116 }
117 }
118
119 Err(MapError::TypeMismatch)
120 }
121
122 pub fn with_mut<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, MapError>
130 where
131 F: FnOnce(&mut V) -> R,
132 {
133 let mut guard = self.items.lock().map_err(|_| MapError::LockError)?;
134 let value = guard
135 .get_mut(key)
136 .ok_or_else(|| MapError::KeyNotFound(format!("{:?}", key)))?;
137
138 if value.concrete_type_id == TypeId::of::<V>() {
139 if let Some(concrete) = value.concrete_value.downcast_mut::<V>() {
140 return Ok(f(concrete));
141 }
142 }
143
144 Err(MapError::TypeMismatch)
145 }
146
147 pub fn with_trait<T, F, R>(&self, key: &K, f: F) -> Result<R, MapError>
158 where
159 T: ?Sized + Any + Send + Sync + 'static,
160 F: FnOnce(&T) -> R,
161 {
162 let guard = self.items.lock().map_err(|_| MapError::LockError)?;
163 let value = guard
164 .get(key)
165 .ok_or_else(|| MapError::KeyNotFound(format!("{:?}", key)))?;
166
167 if value.trait_type_id == TypeId::of::<T>() {
168 if let Some(boxed_trait) = value.trait_object.downcast_ref::<Box<T>>() {
169 return Ok(f(&**boxed_trait));
170 }
171 }
172
173 Err(MapError::TypeMismatch)
174 }
175
176 pub fn remove(&self, key: &K) -> Result<bool, MapError> {
186 let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
187 Ok(store.remove(key).is_some())
188 }
189
190 pub fn contains_key(&self, key: &K) -> Result<bool, MapError> {
196 let store = self.items.lock().map_err(|_| MapError::LockError)?;
197 Ok(store.contains_key(key))
198 }
199
200 pub fn keys(&self) -> Result<Vec<K>, MapError>
206 where
207 K: Clone,
208 {
209 let store = self.items.lock().map_err(|_| MapError::LockError)?;
210 Ok(store.keys().cloned().collect())
211 }
212
213 pub fn len(&self) -> Result<usize, MapError> {
219 let store = self.items.lock().map_err(|_| MapError::LockError)?;
220 Ok(store.len())
221 }
222
223 pub fn is_empty(&self) -> Result<bool, MapError> {
229 let store = self.items.lock().map_err(|_| MapError::LockError)?;
230 Ok(store.is_empty())
231 }
232}
233
234impl<K> Default for TraitTypeMap<K>
235where
236 K: Clone + Eq + Hash + Debug,
237{
238 fn default() -> Self {
239 Self::new()
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246 use std::any::TypeId;
247
248 trait Animal: Any + Send + Sync {
250 fn make_sound(&self) -> String;
251 }
252
253 #[derive(Debug, Clone)]
255 struct Dog {
256 name: String,
257 breed: String,
258 }
259
260 impl Dog {
261 fn wag_tail(&self) -> String {
262 format!("{} wags tail happily!", self.name)
263 }
264 }
265
266 impl Animal for Dog {
267 fn make_sound(&self) -> String {
268 format!("{} says: Woof!", self.name)
269 }
270 }
271
272 impl Into<Box<dyn Animal>> for Dog {
273 fn into(self) -> Box<dyn Animal> {
274 Box::new(self)
275 }
276 }
277
278 #[derive(Debug, Clone)]
279 struct Cat {
280 name: String,
281 lives: u8,
282 }
283
284 impl Cat {
285 fn purr(&self) -> String {
286 format!("{} purrs contentedly", self.name)
287 }
288 }
289
290 impl Animal for Cat {
291 fn make_sound(&self) -> String {
292 format!("{} says: Meow!", self.name)
293 }
294 }
295
296 impl Into<Box<dyn Animal>> for Cat {
297 fn into(self) -> Box<dyn Animal> {
298 Box::new(self)
299 }
300 }
301
302 #[test]
303 fn test_single_type() -> Result<(), MapError> {
304 println!("\nStarting test_single_type");
305 let store = TraitTypeMap::<String>::new();
306
307 let dog = Dog {
308 name: "Rover".to_string(),
309 breed: "Golden Retriever".to_string(),
310 };
311
312 println!("Dog TypeId: {:?}", TypeId::of::<Dog>());
313 println!("Animal TypeId: {:?}", TypeId::of::<dyn Animal>());
314 println!("TypeMapValue TypeId: {:?}", TypeId::of::<TypeMapValue>());
315
316 store.set_trait::<dyn Animal, _>("dog".to_string(), dog)?;
318
319 store.with::<Dog, _, _>(&"dog".to_string(), |dog| {
321 assert_eq!(dog.breed, "Golden Retriever");
322 Ok::<(), MapError>(())
323 })?
324 }
325
326 #[test]
327 fn test_trait_storage_and_access() -> Result<(), MapError> {
328 let store = TraitTypeMap::<String>::new();
329
330 store.set_trait::<dyn Animal, _>(
332 "dog".to_string(),
333 Dog {
334 name: "Rover".to_string(),
335 breed: "Golden Retriever".to_string(),
336 },
337 )?;
338
339 store.set_trait::<dyn Animal, _>(
340 "cat".to_string(),
341 Cat {
342 name: "Whiskers".to_string(),
343 lives: 9,
344 },
345 )?;
346
347 store.with::<Dog, _, _>(&"dog".to_string(), |dog| {
349 assert_eq!(dog.breed, "Golden Retriever");
350 assert_eq!(dog.wag_tail(), "Rover wags tail happily!");
351 })?;
352
353 store.with::<Cat, _, _>(&"cat".to_string(), |cat| {
354 assert_eq!(cat.lives, 9);
355 assert_eq!(cat.purr(), "Whiskers purrs contentedly");
356 })?;
357
358 assert!(store.with::<Cat, _, _>(&"dog".to_string(), |_| {}).is_err());
360 assert!(store.with::<Dog, _, _>(&"cat".to_string(), |_| {}).is_err());
361
362 Ok(())
363 }
364
365 #[test]
366 fn test_mutable_access() -> Result<(), MapError> {
367 let store = TraitTypeMap::<String>::new();
368
369 store.set_trait::<dyn Animal, _>(
371 "cat".to_string(),
372 Cat {
373 name: "Whiskers".to_string(),
374 lives: 9,
375 },
376 )?;
377
378 store.with_mut::<Cat, _, _>(&"cat".to_string(), |cat| {
380 cat.lives -= 1;
381 })?;
382
383 store.with::<Cat, _, _>(&"cat".to_string(), |cat| {
385 assert_eq!(cat.lives, 8);
386 })?;
387
388 Ok(())
389 }
390
391 #[test]
392 fn test_type_errors() {
393 let store = TraitTypeMap::<String>::new();
394
395 store
397 .set_trait::<dyn Animal, _>(
398 "pet".to_string(),
399 Dog {
400 name: "Rover".to_string(),
401 breed: "Golden Retriever".to_string(),
402 },
403 )
404 .unwrap();
405
406 match store.with::<Cat, _, _>(&"pet".to_string(), |_| {}) {
408 Err(MapError::TypeMismatch) => (), _ => panic!("Should have gotten type mismatch error"),
410 }
411
412 match store.with::<Dog, _, _>(&"nonexistent".to_string(), |_| {}) {
414 Err(MapError::KeyNotFound(_)) => (), _ => panic!("Should have gotten key not found error"),
416 }
417 }
418
419 #[test]
420 fn test_trait_access() -> Result<(), MapError> {
421 println!("\nStarting test_trait_access");
422 let store = TraitTypeMap::<String>::new();
423
424 let dog = Dog {
425 name: "Rover".to_string(),
426 breed: "Golden Retriever".to_string(),
427 };
428
429 store.set_trait::<dyn Animal, _>("dog".to_string(), dog)?;
431
432 store.with_trait::<dyn Animal, _, _>(&"dog".to_string(), |animal| {
434 assert_eq!(animal.make_sound(), "Rover says: Woof!");
435 Ok(())
436 })?
437 }
438
439 #[test]
440 fn test_remove() -> Result<(), MapError> {
441 let store = TraitTypeMap::<String>::new();
442
443 store.set_trait::<dyn Animal, _>(
444 "dog".to_string(),
445 Dog {
446 name: "Rover".to_string(),
447 breed: "Golden Retriever".to_string(),
448 },
449 )?;
450
451 assert!(store.contains_key(&"dog".to_string())?);
452 assert!(store.remove(&"dog".to_string())?);
453 assert!(!store.contains_key(&"dog".to_string())?);
454 assert!(!store.remove(&"dog".to_string())?); Ok(())
457 }
458
459 #[test]
460 fn test_keys_len_is_empty() -> Result<(), MapError> {
461 let store = TraitTypeMap::<String>::new();
462
463 assert!(store.is_empty()?);
464 assert_eq!(store.len()?, 0);
465 assert!(store.keys()?.is_empty());
466
467 store.set_trait::<dyn Animal, _>(
468 "dog".to_string(),
469 Dog {
470 name: "Rover".to_string(),
471 breed: "Golden Retriever".to_string(),
472 },
473 )?;
474
475 store.set_trait::<dyn Animal, _>(
476 "cat".to_string(),
477 Cat {
478 name: "Whiskers".to_string(),
479 lives: 9,
480 },
481 )?;
482
483 assert!(!store.is_empty()?);
484 assert_eq!(store.len()?, 2);
485
486 let mut keys = store.keys()?;
487 keys.sort();
488 assert_eq!(keys, vec!["cat".to_string(), "dog".to_string()]);
489
490 Ok(())
491 }
492}