minco_core/
contribution.rs1use crate::{ContributionRegistration, ContributionTypeRegistration, RegistrationOwner, Shared};
2use std::{
3 any::{Any, TypeId},
4 collections::HashMap,
5 fmt,
6 sync::Arc,
7};
8
9#[derive(Default)]
15pub struct ContributionCollection {
16 values: HashMap<TypeId, Vec<Arc<dyn Any + Send + Sync>>>,
17 registrations: HashMap<TypeId, ContributionTypeRegistration>,
18 next_installation_index: usize,
19}
20
21impl std::fmt::Debug for ContributionCollection {
22 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 formatter
24 .debug_struct("ContributionCollection")
25 .field("contribution_types", &self.values.len())
26 .field(
27 "contribution_count",
28 &self.values.values().map(Vec::len).sum::<usize>(),
29 )
30 .field("registration_types", &self.registrations.len())
31 .field("next_installation_index", &self.next_installation_index)
32 .finish()
33 }
34}
35
36impl ContributionCollection {
37 pub fn push<T>(&mut self, value: Arc<T>)
39 where
40 T: Any + Send + Sync,
41 {
42 self.push_owned(value, RegistrationOwner::application());
43 }
44
45 pub(crate) fn push_owned<T>(&mut self, value: Arc<T>, owner: RegistrationOwner)
46 where
47 T: Any + Send + Sync,
48 {
49 let type_id = TypeId::of::<T>();
50 self.values.entry(type_id).or_default().push(value);
51 self.registrations
52 .entry(type_id)
53 .or_insert_with(|| ContributionTypeRegistration {
54 rust_type: std::any::type_name::<T>(),
55 registrations: Vec::new(),
56 })
57 .registrations
58 .push(ContributionRegistration {
59 owner,
60 installation_index: self.next_installation_index,
61 });
62 self.next_installation_index += 1;
63 }
64
65 pub fn push_shared<T>(&mut self, value: Arc<T>)
67 where
68 T: ?Sized + Send + Sync + 'static,
69 {
70 self.push_shared_owned(value, RegistrationOwner::application());
71 }
72
73 pub(crate) fn push_shared_owned<T>(&mut self, value: Arc<T>, owner: RegistrationOwner)
74 where
75 T: ?Sized + Send + Sync + 'static,
76 {
77 self.push_owned(Arc::new(Shared::new(value)), owner);
78 }
79
80 pub fn get<T>(&self) -> Vec<Arc<T>>
82 where
83 T: Any + Send + Sync,
84 {
85 self.values
86 .get(&TypeId::of::<T>())
87 .into_iter()
88 .flatten()
89 .filter_map(|value| Arc::clone(value).downcast::<T>().ok())
90 .collect()
91 }
92
93 pub fn get_shared<T>(&self) -> Vec<Arc<T>>
95 where
96 T: ?Sized + Send + Sync + 'static,
97 {
98 self.get::<Shared<T>>()
99 .into_iter()
100 .map(|value| value.inner())
101 .collect()
102 }
103
104 pub fn freeze(self) -> FrozenContributions {
105 let mut registrations = self.registrations.into_values().collect::<Vec<_>>();
106 registrations.sort_by(|left, right| {
107 let left_index = left
108 .registrations
109 .first()
110 .map_or(usize::MAX, |registration| registration.installation_index);
111 let right_index = right
112 .registrations
113 .first()
114 .map_or(usize::MAX, |registration| registration.installation_index);
115 left.rust_type
116 .cmp(right.rust_type)
117 .then_with(|| left_index.cmp(&right_index))
118 });
119 FrozenContributions {
120 values: self.values,
121 registrations,
122 }
123 }
124}
125
126pub struct ContributionRegistrar<'a> {
131 pub(crate) contributions: &'a mut ContributionCollection,
132 pub(crate) owner: RegistrationOwner,
133}
134
135impl fmt::Debug for ContributionRegistrar<'_> {
136 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
137 formatter
138 .debug_struct("ContributionRegistrar")
139 .field("owner", &self.owner)
140 .finish_non_exhaustive()
141 }
142}
143
144impl ContributionRegistrar<'_> {
145 pub fn push<T>(&mut self, value: Arc<T>)
146 where
147 T: Any + Send + Sync,
148 {
149 self.contributions.push_owned(value, self.owner.clone());
150 }
151
152 pub fn push_shared<T>(&mut self, value: Arc<T>)
153 where
154 T: ?Sized + Send + Sync + 'static,
155 {
156 self.contributions
157 .push_shared_owned(value, self.owner.clone());
158 }
159
160 pub fn get<T>(&self) -> Vec<Arc<T>>
161 where
162 T: Any + Send + Sync,
163 {
164 self.contributions.get::<T>()
165 }
166
167 pub fn get_shared<T>(&self) -> Vec<Arc<T>>
168 where
169 T: ?Sized + Send + Sync + 'static,
170 {
171 self.contributions.get_shared::<T>()
172 }
173}
174
175#[derive(Clone, Default)]
177pub struct FrozenContributions {
178 values: HashMap<TypeId, Vec<Arc<dyn Any + Send + Sync>>>,
179 registrations: Vec<ContributionTypeRegistration>,
180}
181
182impl std::fmt::Debug for FrozenContributions {
183 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184 formatter
185 .debug_struct("FrozenContributions")
186 .field("contribution_types", &self.values.len())
187 .field(
188 "contribution_count",
189 &self.values.values().map(Vec::len).sum::<usize>(),
190 )
191 .field("registration_types", &self.registrations.len())
192 .finish()
193 }
194}
195
196impl FrozenContributions {
197 pub fn registrations(&self) -> &[ContributionTypeRegistration] {
199 &self.registrations
200 }
201
202 pub fn get<T>(&self) -> Vec<Arc<T>>
203 where
204 T: Any + Send + Sync,
205 {
206 self.values
207 .get(&TypeId::of::<T>())
208 .into_iter()
209 .flatten()
210 .filter_map(|value| Arc::clone(value).downcast::<T>().ok())
211 .collect()
212 }
213
214 pub fn get_shared<T>(&self) -> Vec<Arc<T>>
215 where
216 T: ?Sized + Send + Sync + 'static,
217 {
218 self.get::<Shared<T>>()
219 .into_iter()
220 .map(|value| value.inner())
221 .collect()
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 trait Named: Send + Sync {
230 fn name(&self) -> &'static str;
231 }
232
233 #[derive(Debug)]
234 struct First;
235 impl Named for First {
236 fn name(&self) -> &'static str {
237 "first"
238 }
239 }
240
241 #[derive(Debug)]
242 struct Second;
243 impl Named for Second {
244 fn name(&self) -> &'static str {
245 "second"
246 }
247 }
248
249 #[test]
250 fn shared_contributions_preserve_registration_order() {
251 let mut values = ContributionCollection::default();
252 values.push_shared::<dyn Named>(Arc::new(First));
253 values.push_shared::<dyn Named>(Arc::new(Second));
254
255 let frozen = values.freeze();
256 let names = frozen
257 .get_shared::<dyn Named>()
258 .into_iter()
259 .map(|value| value.name())
260 .collect::<Vec<_>>();
261
262 assert_eq!(names, ["first", "second"]);
263 assert_eq!(frozen.registrations().len(), 1);
264 let metadata = &frozen.registrations()[0];
265 assert_eq!(
266 metadata.rust_type,
267 std::any::type_name::<Shared<dyn Named>>()
268 );
269 assert_eq!(
270 metadata
271 .registrations
272 .iter()
273 .map(|registration| registration.installation_index)
274 .collect::<Vec<_>>(),
275 [0, 1]
276 );
277 assert!(
278 metadata
279 .registrations
280 .iter()
281 .all(|registration| registration.owner.is_application())
282 );
283 }
284}