1pub mod factory;
8
9use std::any::{Any, TypeId};
10use std::collections::HashMap;
11use std::sync::Arc;
12use verdure_core::error::component::ComponentError;
13
14pub type ComponentInstance = Arc<dyn Any + Send + Sync>;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum ComponentScope {
30 Singleton,
32 Prototype,
34}
35
36#[derive(Debug)]
64pub struct ComponentDefinition {
65 pub type_id: fn() -> TypeId,
67 pub type_name: &'static str,
69 pub scope: fn() -> ComponentScope,
71 pub dependencies: fn() -> Vec<TypeId>,
73 pub creator:
75 fn(deps: HashMap<TypeId, ComponentInstance>) -> Result<ComponentInstance, ComponentError>,
76}
77
78inventory::collect!(ComponentDefinition);
79
80pub trait ComponentInitializer: Sized {
117 type Dependencies;
119
120 fn __new(deps: Self::Dependencies) -> Self;
126
127 fn __scope() -> ComponentScope;
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[derive(Debug, PartialEq)]
136 struct SimpleComponent {
137 value: i32,
138 }
139
140 #[derive(Debug)]
141 struct ComponentWithDependencies {
142 simple: Arc<SimpleComponent>,
143 message: String,
144 }
145
146 impl ComponentInitializer for SimpleComponent {
147 type Dependencies = ();
148
149 fn __new(_deps: Self::Dependencies) -> Self {
150 SimpleComponent { value: 42 }
151 }
152
153 fn __scope() -> ComponentScope {
154 ComponentScope::Singleton
155 }
156 }
157
158 impl ComponentInitializer for ComponentWithDependencies {
159 type Dependencies = (Arc<SimpleComponent>,);
160
161 fn __new(deps: Self::Dependencies) -> Self {
162 let (simple,) = deps;
163 ComponentWithDependencies {
164 simple,
165 message: "Hello".to_string(),
166 }
167 }
168
169 fn __scope() -> ComponentScope {
170 ComponentScope::Prototype
171 }
172 }
173
174 #[test]
175 fn test_component_scope() {
176 match ComponentScope::Singleton {
177 ComponentScope::Singleton => assert!(true),
178 ComponentScope::Prototype => assert!(false),
179 }
180
181 match ComponentScope::Prototype {
182 ComponentScope::Singleton => assert!(false),
183 ComponentScope::Prototype => assert!(true),
184 }
185 }
186
187 #[test]
188 fn test_simple_component_initializer() {
189 let component = SimpleComponent::__new(());
190 assert_eq!(component.value, 42);
191
192 match SimpleComponent::__scope() {
193 ComponentScope::Singleton => assert!(true),
194 ComponentScope::Prototype => assert!(false),
195 }
196 }
197
198 #[test]
199 fn test_component_with_dependencies_initializer() {
200 let simple_component = Arc::new(SimpleComponent { value: 100 });
201 let deps = (simple_component.clone(),);
202
203 let component = ComponentWithDependencies::__new(deps);
204 assert_eq!(component.simple.value, 100);
205 assert_eq!(component.message, "Hello");
206
207 match ComponentWithDependencies::__scope() {
208 ComponentScope::Singleton => assert!(false),
209 ComponentScope::Prototype => assert!(true),
210 }
211 }
212
213 #[test]
214 fn test_component_definition_structure() {
215 let type_id_fn = || std::any::TypeId::of::<SimpleComponent>();
216 let type_name = "SimpleComponent";
217 let scope_fn = || ComponentScope::Singleton;
218 let dependencies_fn = || vec![];
219 let creator_fn = |deps: HashMap<TypeId, ComponentInstance>| {
220 assert!(deps.is_empty());
221 let instance = SimpleComponent::__new(());
222 Ok(Arc::new(instance) as ComponentInstance)
223 };
224
225 let definition = ComponentDefinition {
226 type_id: type_id_fn,
227 type_name,
228 scope: scope_fn,
229 dependencies: dependencies_fn,
230 creator: creator_fn,
231 };
232
233 assert_eq!((definition.type_id)(), TypeId::of::<SimpleComponent>());
234 assert_eq!(definition.type_name, "SimpleComponent");
235 assert!(matches!((definition.scope)(), ComponentScope::Singleton));
236 assert!((definition.dependencies)().is_empty());
237
238 let result = (definition.creator)(HashMap::new());
239 assert!(result.is_ok());
240 }
241
242 #[test]
243 fn test_component_instance_type() {
244 let simple_component = SimpleComponent { value: 123 };
245 let instance: ComponentInstance = Arc::new(simple_component);
246
247 let downcasted = instance.downcast::<SimpleComponent>();
249 assert!(downcasted.is_ok());
250 assert_eq!(downcasted.unwrap().value, 123);
251 }
252
253 #[test]
254 fn test_component_definition_with_dependencies() {
255 let type_id_fn = || std::any::TypeId::of::<ComponentWithDependencies>();
256 let type_name = "ComponentWithDependencies";
257 let scope_fn = || ComponentScope::Prototype;
258 let dependencies_fn = || vec![TypeId::of::<SimpleComponent>()];
259 let creator_fn = |deps: HashMap<TypeId, ComponentInstance>| {
260 let simple_dep = deps
261 .get(&TypeId::of::<SimpleComponent>())
262 .ok_or_else(|| {
263 verdure_core::error::component::ComponentError::DependencyNotFound(
264 "SimpleComponent".to_string(),
265 )
266 })?
267 .clone()
268 .downcast::<SimpleComponent>()
269 .map_err(|_| {
270 verdure_core::error::component::ComponentError::DowncastFailed(
271 "SimpleComponent".to_string(),
272 )
273 })?;
274
275 let instance = ComponentWithDependencies::__new((simple_dep,));
276 Ok(Arc::new(instance) as ComponentInstance)
277 };
278
279 let definition = ComponentDefinition {
280 type_id: type_id_fn,
281 type_name,
282 scope: scope_fn,
283 dependencies: dependencies_fn,
284 creator: creator_fn,
285 };
286
287 assert_eq!(
288 (definition.type_id)(),
289 TypeId::of::<ComponentWithDependencies>()
290 );
291 assert_eq!(definition.type_name, "ComponentWithDependencies");
292 assert!(matches!((definition.scope)(), ComponentScope::Prototype));
293 assert_eq!(
294 (definition.dependencies)(),
295 vec![TypeId::of::<SimpleComponent>()]
296 );
297
298 let mut deps = HashMap::new();
300 let simple_instance: ComponentInstance = Arc::new(SimpleComponent { value: 999 });
301 deps.insert(TypeId::of::<SimpleComponent>(), simple_instance);
302
303 let result = (definition.creator)(deps);
304 assert!(result.is_ok());
305
306 let component_instance = result.unwrap();
307 let downcasted = component_instance
308 .downcast::<ComponentWithDependencies>()
309 .unwrap();
310 assert_eq!(downcasted.simple.value, 999);
311 assert_eq!(downcasted.message, "Hello");
312 }
313
314 #[test]
315 fn test_component_definition_creator_missing_dependency() {
316 let creator_fn = |deps: HashMap<TypeId, ComponentInstance>| {
317 let _simple_dep = deps.get(&TypeId::of::<SimpleComponent>()).ok_or_else(|| {
318 verdure_core::error::component::ComponentError::DependencyNotFound(
319 "SimpleComponent".to_string(),
320 )
321 })?;
322 Ok(Arc::new(ComponentWithDependencies {
323 simple: Arc::new(SimpleComponent { value: 0 }),
324 message: "test".to_string(),
325 }) as ComponentInstance)
326 };
327
328 let result = creator_fn(HashMap::new());
329 assert!(result.is_err());
330
331 if let Err(error) = result {
332 assert!(matches!(
333 error,
334 verdure_core::error::component::ComponentError::DependencyNotFound(_)
335 ));
336 }
337 }
338}