elif_core/container/
examples.rs

1//! Examples demonstrating the new IoC container features
2
3use crate::container::{IocContainerBuilder, ServiceBinder};
4use crate::errors::CoreError;
5use std::sync::Arc;
6
7/// Example repository trait
8pub trait UserRepository: Send + Sync {
9    fn find_by_id(&self, id: u32) -> Option<String>;
10    fn create(&self, name: &str) -> Result<u32, String>;
11}
12
13/// PostgreSQL implementation
14#[derive(Default)]
15pub struct PostgresUserRepository {
16    connection_string: String,
17}
18
19unsafe impl Send for PostgresUserRepository {}
20unsafe impl Sync for PostgresUserRepository {}
21
22impl PostgresUserRepository {
23    pub fn new(connection_string: String) -> Self {
24        Self { connection_string }
25    }
26}
27
28impl UserRepository for PostgresUserRepository {
29    fn find_by_id(&self, id: u32) -> Option<String> {
30        Some(format!("User {} from {}", id, self.connection_string))
31    }
32
33    fn create(&self, _name: &str) -> Result<u32, String> {
34        Ok(42) // Mock implementation
35    }
36}
37
38/// Example service that depends on repository
39#[derive(Default)]
40pub struct UserService {
41    // In a real implementation, this would be injected
42}
43
44unsafe impl Send for UserService {}
45unsafe impl Sync for UserService {}
46
47impl UserService {
48    pub fn get_user(&self, id: u32) -> Option<String> {
49        // This would use the injected repository
50        Some(format!("User {}", id))
51    }
52}
53
54/// Example demonstrating basic IoC container usage
55pub fn basic_container_example() -> Result<(), CoreError> {
56    let mut builder = IocContainerBuilder::new();
57
58    // Bind services
59    builder
60        .bind_singleton::<PostgresUserRepository, PostgresUserRepository>()
61        .bind::<UserService, UserService>();
62
63    // Build container
64    let container = builder.build()?;
65
66    // Resolve services
67    let repo = container.resolve::<PostgresUserRepository>()?;
68    let user = repo.find_by_id(1);
69    assert!(user.is_some());
70
71    let service = container.resolve::<UserService>()?;
72    let user_data = service.get_user(1);
73    assert!(user_data.is_some());
74
75    Ok(())
76}
77
78/// Example demonstrating named services
79pub fn named_services_example() -> Result<(), CoreError> {
80    let mut builder = IocContainerBuilder::new();
81
82    // Bind multiple implementations with names
83    builder
84        .bind_named::<PostgresUserRepository, PostgresUserRepository>("primary")
85        .bind_named::<PostgresUserRepository, PostgresUserRepository>("backup");
86
87    let container = builder.build()?;
88
89    // Resolve by name
90    let primary_repo = container.resolve_named::<PostgresUserRepository>("primary")?;
91    let backup_repo = container.resolve_named::<PostgresUserRepository>("backup")?;
92
93    assert!(primary_repo.find_by_id(1).is_some());
94    assert!(backup_repo.find_by_id(1).is_some());
95
96    Ok(())
97}
98
99/// Example demonstrating factory-based services
100pub fn factory_services_example() -> Result<(), CoreError> {
101    let mut builder = IocContainerBuilder::new();
102
103    // Bind service with factory
104    builder.bind_factory::<PostgresUserRepository, _, _>(|| {
105        Ok(PostgresUserRepository::new(
106            "postgres://localhost/db".to_string(),
107        ))
108    });
109
110    let container = builder.build()?;
111
112    let repo = container.resolve::<PostgresUserRepository>()?;
113    assert!(repo.find_by_id(1).is_some());
114
115    Ok(())
116}
117
118/// Example demonstrating lifetime behaviors
119pub fn lifetime_example() -> Result<(), CoreError> {
120    let mut builder = IocContainerBuilder::new();
121
122    // Singleton - same instance every time
123    builder.bind_singleton::<UserService, UserService>();
124
125    // Transient - new instance every time
126    builder.bind_transient::<PostgresUserRepository, PostgresUserRepository>();
127
128    let container = builder.build()?;
129
130    // Singleton behavior
131    let service1 = container.resolve::<UserService>()?;
132    let service2 = container.resolve::<UserService>()?;
133    assert!(Arc::ptr_eq(&service1, &service2));
134
135    // Transient behavior
136    let repo1 = container.resolve::<PostgresUserRepository>()?;
137    let repo2 = container.resolve::<PostgresUserRepository>()?;
138    assert!(!Arc::ptr_eq(&repo1, &repo2));
139
140    Ok(())
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146
147    #[test]
148    fn test_basic_container_example() {
149        basic_container_example().unwrap();
150    }
151
152    #[test]
153    fn test_named_services_example() {
154        named_services_example().unwrap();
155    }
156
157    #[test]
158    fn test_factory_services_example() {
159        factory_services_example().unwrap();
160    }
161
162    #[test]
163    fn test_lifetime_example() {
164        lifetime_example().unwrap();
165    }
166}