aopt_core/
map.rs

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}