1use std::any::TypeId;
2use std::collections::hash_map::Entry as MapEntry;
3use std::fmt::Debug;
4use std::marker::PhantomData;
5
6use crate::typeid;
7use crate::HashMap;
8
9#[cfg(all(feature = "sync", not(feature = "log")))]
10mod __erased_ty {
11 use std::any::Any;
12
13 pub trait ErasedTy: Any + Sync + Send + 'static {}
14
15 impl<T: Any + Sync + Send + 'static> ErasedTy for T {}
16
17 pub type BoxedAny = Box<dyn Any + Send + Sync>;
18}
19
20#[cfg(all(feature = "sync", feature = "log"))]
21mod __erased_ty {
22
23 use std::any::Any;
24 use std::fmt::Debug;
25
26 pub trait ErasedTy: Any + Debug + Sync + Send + 'static {}
27
28 impl<T: Any + Debug + Sync + Send + 'static> ErasedTy for T {}
29
30 pub type BoxedAny = Box<dyn Any + Send + Sync>;
31}
32
33#[cfg(all(not(feature = "sync"), not(feature = "log")))]
34mod __erased_ty {
35 use std::any::Any;
36
37 pub trait ErasedTy: Any + 'static {}
38
39 impl<T: Any + 'static> ErasedTy for T {}
40
41 pub type BoxedAny = Box<dyn Any>;
42}
43
44#[cfg(all(not(feature = "sync"), feature = "log"))]
45mod __erased_ty {
46 use std::any::Any;
47 use std::fmt::Debug;
48
49 pub trait ErasedTy: Any + Debug + 'static {}
50
51 impl<T: Any + Debug + 'static> ErasedTy for T {}
52
53 pub type BoxedAny = Box<dyn Any>;
54}
55
56pub use __erased_ty::*;
57
58#[derive(Default)]
59pub struct AnyMap(pub(crate) HashMap<TypeId, BoxedAny>);
60
61impl Debug for AnyMap {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 let field_ids = self
64 .0
65 .iter()
66 .map(|v| format!("{:?}", v.0))
67 .collect::<Vec<String>>()
68 .join(", ");
69 f.debug_tuple("AnyMap")
70 .field(&format!("[{field_ids}]",))
71 .finish()
72 }
73}
74
75impl AnyMap {
76 pub fn with_value<T: ErasedTy>(mut self, value: T) -> Self {
77 self.0.insert(typeid::<T>(), Box::new(value));
78 self
79 }
80}
81
82impl AnyMap {
83 pub fn new() -> Self {
84 Self(HashMap::default())
85 }
86
87 pub fn len(&self) -> usize {
88 self.0.len()
89 }
90
91 pub fn clear(&mut self) {
92 self.0.clear()
93 }
94
95 pub fn is_empty(&self) -> bool {
96 self.0.is_empty()
97 }
98
99 pub fn contain<T: ErasedTy>(&self) -> bool {
100 self.0.contains_key(&typeid::<T>())
101 }
102
103 pub fn entry<T: ErasedTy>(&mut self) -> Entry<'_, T> {
104 Entry::new(self.0.entry(typeid::<T>()))
105 }
106
107 pub fn insert<T: ErasedTy>(&mut self, value: T) -> Option<T> {
108 self.0
109 .insert(typeid::<T>(), Box::new(value))
110 .and_then(|v| v.downcast().ok().map(|v| *v))
111 }
112
113 pub fn remove<T: ErasedTy>(&mut self) -> Option<T> {
114 self.0
115 .remove(&typeid::<T>())
116 .and_then(|v| v.downcast().ok().map(|v| *v))
117 }
118
119 pub fn value<T: ErasedTy>(&self) -> Option<&T> {
120 self.0.get(&typeid::<T>()).and_then(|v| v.downcast_ref())
121 }
122
123 pub fn value_mut<T: ErasedTy>(&mut self) -> Option<&mut T> {
124 self.0
125 .get_mut(&typeid::<T>())
126 .and_then(|v| v.downcast_mut())
127 }
128}
129
130pub struct Entry<'a, T> {
131 inner: MapEntry<'a, TypeId, BoxedAny>,
132
133 marker: PhantomData<T>,
134}
135
136impl<'a, T> Entry<'a, T>
137where
138 T: ErasedTy,
139{
140 pub fn new(entry: MapEntry<'a, TypeId, BoxedAny>) -> Self {
141 Self {
142 inner: entry,
143 marker: PhantomData,
144 }
145 }
146
147 pub fn key(&self) -> &TypeId {
148 self.inner.key()
149 }
150
151 pub fn or_insert(self, val: T) -> &'a mut T {
152 self.inner
153 .or_insert_with(|| Box::new(val))
154 .downcast_mut::<T>()
155 .unwrap()
156 }
157
158 pub fn or_insert_with<F>(self, f: F) -> &'a mut T
159 where
160 F: FnOnce() -> T,
161 {
162 self.or_insert(f())
163 }
164
165 pub fn or_insert_with_key<F>(self, f: F) -> &'a mut T
166 where
167 F: FnOnce(&TypeId) -> T,
168 {
169 let val = f(self.key());
170 self.or_insert(val)
171 }
172
173 pub fn and_modify<F>(mut self, f: F) -> Self
174 where
175 F: FnOnce(&mut T),
176 {
177 self.inner = self.inner.and_modify(|v| f(v.downcast_mut::<T>().unwrap()));
178 self
179 }
180}
181
182impl<'a, T> Entry<'a, T>
183where
184 T: ErasedTy + Default,
185{
186 #[allow(clippy::or_fun_call)]
187 pub fn or_default(self) -> &'a mut T {
188 self.or_insert_with(|| T::default())
189 }
190}