minco_core/
contribution.rs1use crate::Shared;
2use std::{
3 any::{Any, TypeId},
4 collections::HashMap,
5 sync::Arc,
6};
7
8#[derive(Default)]
14pub struct ContributionCollection {
15 values: HashMap<TypeId, Vec<Arc<dyn Any + Send + Sync>>>,
16}
17
18impl std::fmt::Debug for ContributionCollection {
19 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 formatter
21 .debug_struct("ContributionCollection")
22 .field("contribution_types", &self.values.len())
23 .field(
24 "contribution_count",
25 &self.values.values().map(Vec::len).sum::<usize>(),
26 )
27 .finish()
28 }
29}
30
31impl ContributionCollection {
32 pub fn push<T>(&mut self, value: Arc<T>)
34 where
35 T: Any + Send + Sync,
36 {
37 self.values
38 .entry(TypeId::of::<T>())
39 .or_default()
40 .push(value);
41 }
42
43 pub fn push_shared<T>(&mut self, value: Arc<T>)
45 where
46 T: ?Sized + Send + Sync + 'static,
47 {
48 self.push(Arc::new(Shared::new(value)));
49 }
50
51 pub fn get<T>(&self) -> Vec<Arc<T>>
53 where
54 T: Any + Send + Sync,
55 {
56 self.values
57 .get(&TypeId::of::<T>())
58 .into_iter()
59 .flatten()
60 .filter_map(|value| Arc::clone(value).downcast::<T>().ok())
61 .collect()
62 }
63
64 pub fn get_shared<T>(&self) -> Vec<Arc<T>>
66 where
67 T: ?Sized + Send + Sync + 'static,
68 {
69 self.get::<Shared<T>>()
70 .into_iter()
71 .map(|value| value.inner())
72 .collect()
73 }
74
75 pub fn freeze(self) -> FrozenContributions {
76 FrozenContributions {
77 values: self.values,
78 }
79 }
80}
81
82#[derive(Clone, Default)]
84pub struct FrozenContributions {
85 values: HashMap<TypeId, Vec<Arc<dyn Any + Send + Sync>>>,
86}
87
88impl std::fmt::Debug for FrozenContributions {
89 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 formatter
91 .debug_struct("FrozenContributions")
92 .field("contribution_types", &self.values.len())
93 .field(
94 "contribution_count",
95 &self.values.values().map(Vec::len).sum::<usize>(),
96 )
97 .finish()
98 }
99}
100
101impl FrozenContributions {
102 pub fn get<T>(&self) -> Vec<Arc<T>>
103 where
104 T: Any + Send + Sync,
105 {
106 self.values
107 .get(&TypeId::of::<T>())
108 .into_iter()
109 .flatten()
110 .filter_map(|value| Arc::clone(value).downcast::<T>().ok())
111 .collect()
112 }
113
114 pub fn get_shared<T>(&self) -> Vec<Arc<T>>
115 where
116 T: ?Sized + Send + Sync + 'static,
117 {
118 self.get::<Shared<T>>()
119 .into_iter()
120 .map(|value| value.inner())
121 .collect()
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 trait Named: Send + Sync {
130 fn name(&self) -> &'static str;
131 }
132
133 #[derive(Debug)]
134 struct First;
135 impl Named for First {
136 fn name(&self) -> &'static str {
137 "first"
138 }
139 }
140
141 #[derive(Debug)]
142 struct Second;
143 impl Named for Second {
144 fn name(&self) -> &'static str {
145 "second"
146 }
147 }
148
149 #[test]
150 fn shared_contributions_preserve_registration_order() {
151 let mut values = ContributionCollection::default();
152 values.push_shared::<dyn Named>(Arc::new(First));
153 values.push_shared::<dyn Named>(Arc::new(Second));
154
155 let names = values
156 .freeze()
157 .get_shared::<dyn Named>()
158 .into_iter()
159 .map(|value| value.name())
160 .collect::<Vec<_>>();
161
162 assert_eq!(names, ["first", "second"]);
163 }
164}