elif_core/container/
ioc_builder.rs

1use crate::container::autowiring::Injectable;
2use crate::container::binding::{ServiceBinder, ServiceBindings};
3use crate::container::ioc_container::IocContainer;
4use crate::errors::CoreError;
5
6/// Builder for IoC container with fluent API
7#[derive(Debug)]
8pub struct IocContainerBuilder {
9    bindings: ServiceBindings,
10}
11
12impl IocContainerBuilder {
13    /// Create a new IoC container builder
14    pub fn new() -> Self {
15        Self {
16            bindings: ServiceBindings::new(),
17        }
18    }
19
20    /// Build the IoC container
21    pub fn build(self) -> Result<IocContainer, CoreError> {
22        let mut container = IocContainer::from_bindings(self.bindings);
23        container.build()?;
24        Ok(container)
25    }
26}
27
28impl ServiceBinder for IocContainerBuilder {
29    fn add_service_descriptor(
30        &mut self,
31        descriptor: crate::container::descriptor::ServiceDescriptor,
32    ) -> Result<&mut Self, crate::errors::CoreError> {
33        self.bindings.add_descriptor(descriptor);
34        Ok(self)
35    }
36
37    fn bind<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
38        &mut self,
39    ) -> &mut Self {
40        self.bindings.bind::<TInterface, TImpl>();
41        self
42    }
43
44    fn bind_singleton<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
45        &mut self,
46    ) -> &mut Self {
47        self.bindings.bind_singleton::<TInterface, TImpl>();
48        self
49    }
50
51    fn bind_transient<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
52        &mut self,
53    ) -> &mut Self {
54        self.bindings.bind_transient::<TInterface, TImpl>();
55        self
56    }
57
58    fn bind_factory<TInterface: ?Sized + 'static, F, T>(&mut self, factory: F) -> &mut Self
59    where
60        F: Fn() -> Result<T, CoreError> + Send + Sync + 'static,
61        T: Send + Sync + 'static,
62    {
63        self.bindings.bind_factory::<TInterface, _, _>(factory);
64        self
65    }
66
67    fn bind_instance<TInterface: ?Sized + 'static, TImpl: Send + Sync + Clone + 'static>(
68        &mut self,
69        instance: TImpl,
70    ) -> &mut Self {
71        self.bindings.bind_instance::<TInterface, TImpl>(instance);
72        self
73    }
74
75    fn bind_named<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
76        &mut self,
77        name: &str,
78    ) -> &mut Self {
79        self.bindings.bind_named::<TInterface, TImpl>(name);
80        self
81    }
82
83    fn bind_injectable<T: Injectable>(&mut self) -> &mut Self {
84        self.bindings.bind_injectable::<T>();
85        self
86    }
87
88    fn bind_injectable_singleton<T: Injectable>(&mut self) -> &mut Self {
89        self.bindings.bind_injectable_singleton::<T>();
90        self
91    }
92
93    // Advanced binding methods implementation
94
95    fn bind_with<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
96        &mut self,
97    ) -> crate::container::binding::AdvancedBindingBuilder<TInterface> {
98        self.bindings.bind_with::<TInterface, TImpl>()
99    }
100
101    fn with_implementation<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
102        &mut self,
103        config: crate::container::binding::BindingConfig,
104    ) -> &mut Self {
105        self.bindings
106            .with_implementation::<TInterface, TImpl>(config);
107        self
108    }
109
110    fn bind_lazy<TInterface: ?Sized + 'static, F, T>(&mut self, factory: F) -> &mut Self
111    where
112        F: Fn() -> T + Send + Sync + 'static,
113        T: Send + Sync + 'static,
114    {
115        self.bindings.bind_lazy::<TInterface, F, T>(factory);
116        self
117    }
118
119    fn bind_parameterized_factory<TInterface: ?Sized + 'static, P, F, T>(
120        &mut self,
121        factory: F,
122    ) -> &mut Self
123    where
124        F: Fn(P) -> Result<T, CoreError> + Send + Sync + 'static,
125        T: Send + Sync + 'static,
126        P: Send + Sync + 'static,
127    {
128        self.bindings
129            .bind_parameterized_factory::<TInterface, P, F, T>(factory);
130        self
131    }
132
133    fn bind_collection<TInterface: ?Sized + 'static, F>(&mut self, configure: F) -> &mut Self
134    where
135        F: FnOnce(&mut crate::container::binding::CollectionBindingBuilder<TInterface>),
136    {
137        self.bindings.bind_collection::<TInterface, F>(configure);
138        self
139    }
140}
141
142impl Default for IocContainerBuilder {
143    fn default() -> Self {
144        Self::new()
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use super::*;
151
152    trait TestService: Send + Sync {
153        fn get_value(&self) -> String;
154    }
155
156    #[derive(Default)]
157    struct TestServiceImpl;
158
159    unsafe impl Send for TestServiceImpl {}
160    unsafe impl Sync for TestServiceImpl {}
161
162    impl TestService for TestServiceImpl {
163        fn get_value(&self) -> String {
164            "test_value".to_string()
165        }
166    }
167
168    #[test]
169    fn test_ioc_container_builder() {
170        let mut builder = IocContainerBuilder::new();
171        builder.bind::<TestServiceImpl, TestServiceImpl>();
172        let container = builder.build().unwrap();
173
174        let service = container.resolve::<TestServiceImpl>().unwrap();
175        assert_eq!(service.get_value(), "test_value");
176    }
177
178    #[test]
179    fn test_builder_chaining() {
180        let mut builder = IocContainerBuilder::new();
181
182        builder
183            .bind::<TestServiceImpl, TestServiceImpl>()
184            .bind_singleton::<TestServiceImpl, TestServiceImpl>()
185            .bind_transient::<TestServiceImpl, TestServiceImpl>();
186
187        // Should have multiple bindings (will be deduplicated by service ID)
188        assert!(builder.bindings.count() > 0);
189    }
190}