bitwarden_state/
any_map.rs1use std::{
2 any::{Any, TypeId},
3 collections::HashMap,
4 sync::RwLock,
5};
6
7pub(crate) struct AnyMap {
9 inner: RwLock<HashMap<TypeId, Box<dyn Any + Send + Sync>>>,
10}
11
12impl AnyMap {
13 pub(crate) fn new() -> Self {
15 Self {
16 inner: RwLock::new(HashMap::new()),
17 }
18 }
19
20 pub(crate) fn insert<V: Send + Sync + 'static>(&self, value: V) {
25 self.inner
26 .write()
27 .expect("RwLock should not be poisoned")
28 .insert(TypeId::of::<V>(), Box::new(value));
29 }
30
31 pub(crate) fn get<V: Clone + Send + Sync + 'static>(&self) -> Option<V> {
33 self.inner
34 .read()
35 .expect("RwLock should not be poisoned")
36 .get(&TypeId::of::<V>())
37 .and_then(|value| value.downcast_ref::<V>())
38 .cloned()
39 }
40
41 pub(crate) fn clear(&self) {
43 self.inner
44 .write()
45 .expect("RwLock should not be poisoned")
46 .clear();
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn test_roundtrip() {
56 let map = AnyMap::new();
57
58 map.insert(42_u32);
59 map.insert("hello".to_string());
60
61 assert_eq!(map.get::<u32>(), Some(42));
62 assert_eq!(map.get::<String>(), Some("hello".to_string()));
63 }
64
65 #[test]
66 fn test_get_missing_type_returns_none() {
67 let map = AnyMap::new();
68 map.insert(42_u32);
69
70 assert_eq!(map.get::<String>(), None);
71 assert_eq!(map.get::<u8>(), None);
72 }
73
74 #[test]
75 fn test_insert_overwrites() {
76 let map = AnyMap::new();
77
78 map.insert(1_u32);
79 map.insert(2_u32);
80
81 assert_eq!(map.get::<u32>(), Some(2));
82 }
83
84 #[test]
85 fn test_clear() {
86 let map = AnyMap::new();
87 map.insert(1_u32);
88 map.insert("a".to_string());
89
90 map.clear();
91
92 assert_eq!(map.get::<u32>(), None);
93 assert_eq!(map.get::<String>(), None);
94 }
95}