elif_core/container/
builder.rs

1use crate::container::{Container, ServiceRegistry, ServiceScope};
2use crate::errors::CoreError;
3use crate::foundation::traits::Service;
4
5/// Builder for constructing containers with services
6pub struct ContainerBuilder {
7    registry: ServiceRegistry,
8    scope: ServiceScope,
9}
10
11impl ContainerBuilder {
12    /// Create a new container builder
13    pub fn new() -> Self {
14        Self {
15            registry: ServiceRegistry::new(),
16            scope: ServiceScope::Singleton,
17        }
18    }
19
20    /// Set the default scope for services
21    pub fn with_scope(mut self, scope: ServiceScope) -> Self {
22        self.scope = scope;
23        self
24    }
25
26    /// Add a service to the container
27    pub fn add_service<T>(mut self, service: T) -> Result<Self, CoreError>
28    where
29        T: Service + Clone + 'static,
30    {
31        self.registry.register_service(service)?;
32        Ok(self)
33    }
34
35    /// Add a singleton service
36    pub fn add_singleton<T>(mut self, service: T) -> Result<Self, CoreError>
37    where
38        T: Service + Clone + 'static,
39    {
40        self.registry.register_singleton(service)?;
41        Ok(self)
42    }
43
44    /// Add a transient service with factory
45    pub fn add_transient<T>(
46        mut self,
47        factory: Box<dyn Fn() -> T + Send + Sync>,
48    ) -> Result<Self, CoreError>
49    where
50        T: Service + 'static,
51    {
52        self.registry.register_transient(factory)?;
53        Ok(self)
54    }
55
56    /// Add multiple services at once
57    pub fn add_services<T>(mut self, services: Vec<T>) -> Result<Self, CoreError>
58    where
59        T: Service + Clone + 'static,
60    {
61        for service in services {
62            self.registry.register_service(service)?;
63        }
64        Ok(self)
65    }
66
67    /// Configure the builder from a configuration closure
68    pub fn configure<F>(self, configure: F) -> Result<Self, CoreError>
69    where
70        F: FnOnce(Self) -> Result<Self, CoreError>,
71    {
72        configure(self)
73    }
74
75    /// Build the container
76    pub fn build(self) -> Result<Container, CoreError> {
77        let container = Container::new();
78        // TODO: Implement proper service transfer from builder registry to container
79        container.validate()?;
80        Ok(container)
81    }
82
83    /// Build and initialize the container
84    pub async fn build_and_initialize(self) -> Result<Container, CoreError> {
85        let mut container = self.build()?;
86        container.initialize().await?;
87        Ok(container)
88    }
89}
90
91impl Default for ContainerBuilder {
92    fn default() -> Self {
93        Self::new()
94    }
95}
96
97/// Convenience macro for building containers
98#[macro_export]
99macro_rules! container {
100    ($($service:expr),* $(,)?) => {
101        {
102            let mut builder = $crate::container::ContainerBuilder::new();
103            $(
104                builder = builder.add_service($service)?;
105            )*
106            builder.build()
107        }
108    };
109}
110
111/// Convenience macro for building containers with singletons
112#[macro_export]
113macro_rules! singleton_container {
114    ($($service:expr),* $(,)?) => {
115        {
116            let mut builder = $crate::container::ContainerBuilder::new()
117                .with_scope($crate::container::ServiceScope::Singleton);
118            $(
119                builder = builder.add_singleton($service)?;
120            )*
121            builder.build()
122        }
123    };
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129    use crate::foundation::traits::{FrameworkComponent, Service};
130
131    #[derive(Clone, Debug)]
132    #[allow(dead_code)]
133    struct TestService {
134        name: String,
135    }
136
137    impl FrameworkComponent for TestService {}
138    impl Service for TestService {}
139
140    impl TestService {
141        fn new(name: &str) -> Self {
142            Self {
143                name: name.to_string(),
144            }
145        }
146    }
147
148    #[tokio::test]
149    async fn test_container_builder() -> Result<(), CoreError> {
150        let container = ContainerBuilder::new()
151            .add_service(TestService::new("test1"))?
152            .add_singleton(TestService::new("test2"))?
153            .build_and_initialize()
154            .await?;
155
156        // TODO: Fix service transfer from builder to container
157        // assert_eq!(container.service_count(), 2);
158        assert!(container.is_initialized());
159
160        Ok(())
161    }
162}