1use std::any::{Any, TypeId, type_name};
4use std::collections::HashMap;
5use std::sync::Arc;
6
7type CloneFn = Arc<dyn Fn(&dyn Any) -> Box<dyn Any + Send + Sync> + Send + Sync>;
8
9struct Entry {
10 value: Box<dyn Any + Send + Sync>,
11 clone_fn: CloneFn,
12}
13
14impl Clone for Entry {
15 fn clone(&self) -> Self {
16 Self {
17 value: (self.clone_fn)(self.value.as_ref()),
18 clone_fn: Arc::clone(&self.clone_fn),
19 }
20 }
21}
22
23#[derive(Clone)]
25pub struct AroState {
26 services: HashMap<TypeId, Entry>,
27}
28
29impl std::fmt::Debug for AroState {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 f.debug_struct("AroState")
32 .field("services", &format!("{} registered", self.services.len()))
33 .finish()
34 }
35}
36
37impl AroState {
38 pub fn builder() -> AroStateBuilder {
40 AroStateBuilder {
41 services: HashMap::new(),
42 }
43 }
44
45 pub fn get<T: ?Sized + 'static>(&self) -> Option<Arc<T>>
47 where
48 Arc<T>: 'static,
49 {
50 self.services
51 .get(&TypeId::of::<Arc<T>>())
52 .and_then(|entry| entry.value.downcast_ref::<Arc<T>>())
53 .cloned()
54 }
55
56 #[must_use]
58 pub fn merge(mut self, other: Self) -> Self {
59 self.services.extend(other.services);
60 self
61 }
62
63 pub fn validate_dep<T: ?Sized + 'static>(&self) -> Result<(), String>
65 where
66 Arc<T>: 'static,
67 {
68 if self.get::<T>().is_some() {
69 Ok(())
70 } else {
71 Err(format!("missing dependency: {}", type_name::<T>()))
72 }
73 }
74}
75
76pub struct AroStateBuilder {
78 services: HashMap<TypeId, Entry>,
79}
80
81impl AroStateBuilder {
82 #[must_use]
84 #[expect(
85 clippy::expect_used,
86 reason = "type mismatch in clone_fn indicates a bug in AroState internals"
87 )]
88 pub fn register<T: ?Sized + 'static>(mut self, service: Arc<T>) -> Self
89 where
90 Arc<T>: Send + Sync + Clone + 'static,
91 {
92 let clone_fn: CloneFn = Arc::new(|any: &dyn Any| {
93 let arc = any
94 .downcast_ref::<Arc<T>>()
95 .expect("type mismatch in AroState clone");
96 Box::new(arc.clone())
97 });
98 self.services.insert(
99 TypeId::of::<Arc<T>>(),
100 Entry {
101 value: Box::new(service),
102 clone_fn,
103 },
104 );
105 self
106 }
107
108 pub fn build(self) -> AroState {
110 AroState {
111 services: self.services,
112 }
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 trait Greeter: Send + Sync {
121 fn greet(&self) -> &'static str;
122 }
123
124 struct HelloGreeter;
125 impl Greeter for HelloGreeter {
126 fn greet(&self) -> &'static str {
127 "hello"
128 }
129 }
130
131 trait Counter: Send + Sync {
132 fn count(&self) -> u32;
133 }
134
135 struct FixedCounter(u32);
136 impl Counter for FixedCounter {
137 fn count(&self) -> u32 {
138 self.0
139 }
140 }
141
142 #[test]
143 fn register_and_retrieve_service() {
144 let state = AroState::builder()
145 .register::<dyn Greeter>(Arc::new(HelloGreeter))
146 .build();
147 let greeter = state.get::<dyn Greeter>().unwrap();
148 assert_eq!(greeter.greet(), "hello");
149 }
150
151 #[test]
152 fn missing_service_returns_none() {
153 let state = AroState::builder().build();
154 assert!(state.get::<dyn Greeter>().is_none());
155 }
156
157 #[test]
158 fn multiple_services() {
159 let state = AroState::builder()
160 .register::<dyn Greeter>(Arc::new(HelloGreeter))
161 .register::<dyn Counter>(Arc::new(FixedCounter(42)))
162 .build();
163 assert_eq!(state.get::<dyn Greeter>().unwrap().greet(), "hello");
164 assert_eq!(state.get::<dyn Counter>().unwrap().count(), 42);
165 }
166
167 #[test]
168 fn validate_dep_succeeds_when_registered() {
169 let state = AroState::builder()
170 .register::<dyn Greeter>(Arc::new(HelloGreeter))
171 .build();
172 assert!(state.validate_dep::<dyn Greeter>().is_ok());
173 }
174
175 #[test]
176 fn validate_dep_fails_when_missing() {
177 let state = AroState::builder().build();
178 let err = state.validate_dep::<dyn Greeter>().unwrap_err();
179 assert!(err.contains("missing dependency"));
180 }
181
182 #[test]
183 fn state_is_clone() {
184 let state = AroState::builder()
185 .register::<dyn Greeter>(Arc::new(HelloGreeter))
186 .build();
187 let cloned = state.clone();
188 assert_eq!(cloned.get::<dyn Greeter>().unwrap().greet(), "hello");
189 }
190
191 #[test]
192 fn merge_preserves_both_types() {
193 let state_a = AroState::builder()
194 .register::<dyn Greeter>(Arc::new(HelloGreeter))
195 .build();
196 let state_b = AroState::builder()
197 .register::<dyn Counter>(Arc::new(FixedCounter(7)))
198 .build();
199
200 let merged = state_a.merge(state_b);
201 assert_eq!(merged.get::<dyn Greeter>().unwrap().greet(), "hello");
202 assert_eq!(merged.get::<dyn Counter>().unwrap().count(), 7);
203 }
204
205 #[test]
206 fn merge_overwrites_existing_type() {
207 struct AltGreeter;
208 impl Greeter for AltGreeter {
209 fn greet(&self) -> &'static str {
210 "hi"
211 }
212 }
213
214 let state_a = AroState::builder()
215 .register::<dyn Greeter>(Arc::new(HelloGreeter))
216 .build();
217 let state_b = AroState::builder()
218 .register::<dyn Greeter>(Arc::new(AltGreeter))
219 .build();
220
221 let merged = state_a.merge(state_b);
222 assert_eq!(merged.get::<dyn Greeter>().unwrap().greet(), "hi");
223 }
224
225 #[test]
226 fn merge_preserves_unrelated_types() {
227 let state_a = AroState::builder()
228 .register::<dyn Greeter>(Arc::new(HelloGreeter))
229 .register::<dyn Counter>(Arc::new(FixedCounter(1)))
230 .build();
231 let state_b = AroState::builder()
232 .register::<dyn Counter>(Arc::new(FixedCounter(99)))
233 .build();
234
235 let merged = state_a.merge(state_b);
236 assert_eq!(merged.get::<dyn Greeter>().unwrap().greet(), "hello");
238 assert_eq!(merged.get::<dyn Counter>().unwrap().count(), 99);
240 }
241}