1use crate::container::{AdvancedBindingBuilder, IocContainer, ServiceBinder, ServiceScope};
12use crate::errors::CoreError;
13use std::collections::HashMap;
14
15pub trait Cache: Send + Sync {
19 fn get(&self, key: &str) -> Option<String>;
20 fn set(&self, key: &str, value: String) -> Result<(), String>;
21 fn delete(&self, key: &str) -> Result<(), String>;
22}
23
24#[derive(Default)]
26pub struct RedisCache {
27 _config: String,
28}
29
30impl Cache for RedisCache {
31 fn get(&self, key: &str) -> Option<String> {
32 println!("RedisCache: Getting key '{}'", key);
33 Some(format!("redis_value_{}", key))
34 }
35
36 fn set(&self, key: &str, value: String) -> Result<(), String> {
37 println!("RedisCache: Setting '{}' = '{}'", key, value);
38 Ok(())
39 }
40
41 fn delete(&self, key: &str) -> Result<(), String> {
42 println!("RedisCache: Deleting key '{}'", key);
43 Ok(())
44 }
45}
46
47#[derive(Default)]
49pub struct MemoryCache {
50 storage: HashMap<String, String>,
51}
52
53impl Cache for MemoryCache {
54 fn get(&self, key: &str) -> Option<String> {
55 println!("MemoryCache: Getting key '{}'", key);
56 self.storage.get(key).cloned()
57 }
58
59 fn set(&self, key: &str, value: String) -> Result<(), String> {
60 println!("MemoryCache: Setting '{}' = '{}'", key, value);
61 Ok(())
63 }
64
65 fn delete(&self, key: &str) -> Result<(), String> {
66 println!("MemoryCache: Deleting key '{}'", key);
67 Ok(())
68 }
69}
70
71#[derive(Default)]
73pub struct HybridCache;
74
75impl Cache for HybridCache {
76 fn get(&self, key: &str) -> Option<String> {
77 println!(
78 "HybridCache: Getting key '{}' (checking memory first, then Redis)",
79 key
80 );
81 Some(format!("hybrid_value_{}", key))
82 }
83
84 fn set(&self, key: &str, value: String) -> Result<(), String> {
85 println!(
86 "HybridCache: Setting '{}' = '{}' (both memory and Redis)",
87 key, value
88 );
89 Ok(())
90 }
91
92 fn delete(&self, key: &str) -> Result<(), String> {
93 println!(
94 "HybridCache: Deleting key '{}' (from both memory and Redis)",
95 key
96 );
97 Ok(())
98 }
99}
100
101pub trait EmailService: Send + Sync {
103 fn send_email(&self, to: &str, subject: &str, body: &str) -> Result<(), String>;
104}
105
106#[derive(Default)]
108pub struct SmtpEmailService;
109
110impl EmailService for SmtpEmailService {
111 fn send_email(&self, to: &str, subject: &str, body: &str) -> Result<(), String> {
112 println!("SMTP: Sending email to '{}' with subject '{}'", to, subject);
113 println!("Body: {}", body);
114 Ok(())
115 }
116}
117
118#[derive(Default)]
120pub struct SendGridEmailService;
121
122impl EmailService for SendGridEmailService {
123 fn send_email(&self, to: &str, subject: &str, body: &str) -> Result<(), String> {
124 println!(
125 "SendGrid API: Sending email to '{}' with subject '{}'",
126 to, subject
127 );
128 println!("Body: {}", body);
129 Ok(())
130 }
131}
132
133pub trait Storage: Send + Sync {
135 fn store(&self, path: &str, data: &[u8]) -> Result<String, String>;
136 fn retrieve(&self, path: &str) -> Result<Vec<u8>, String>;
137}
138
139#[derive(Default)]
141pub struct LocalStorage;
142
143impl Storage for LocalStorage {
144 fn store(&self, path: &str, data: &[u8]) -> Result<String, String> {
145 println!("LocalStorage: Storing {} bytes to '{}'", data.len(), path);
146 Ok(format!("/local/{}", path))
147 }
148
149 fn retrieve(&self, path: &str) -> Result<Vec<u8>, String> {
150 println!("LocalStorage: Retrieving from '{}'", path);
151 Ok(b"local file content".to_vec())
152 }
153}
154
155#[derive(Default)]
157pub struct S3Storage;
158
159impl Storage for S3Storage {
160 fn store(&self, path: &str, data: &[u8]) -> Result<String, String> {
161 println!("S3Storage: Storing {} bytes to '{}'", data.len(), path);
162 Ok(format!("https://bucket.s3.amazonaws.com/{}", path))
163 }
164
165 fn retrieve(&self, path: &str) -> Result<Vec<u8>, String> {
166 println!("S3Storage: Retrieving from '{}'", path);
167 Ok(b"s3 file content".to_vec())
168 }
169}
170
171pub fn example_environment_based_binding() -> Result<IocContainer, CoreError> {
173 let mut container = IocContainer::new();
174
175 let redis_config = AdvancedBindingBuilder::<dyn Cache>::new()
177 .named("redis")
178 .when_env("CACHE_PROVIDER", "redis")
179 .with_lifetime(ServiceScope::Singleton)
180 .config();
181 container.with_implementation::<dyn Cache, RedisCache>(redis_config);
182
183 let memory_config = AdvancedBindingBuilder::<dyn Cache>::new()
185 .named("memory")
186 .when_env("CACHE_PROVIDER", "memory")
187 .with_lifetime(ServiceScope::Singleton)
188 .config();
189 container.with_implementation::<dyn Cache, MemoryCache>(memory_config);
190
191 let hybrid_config = AdvancedBindingBuilder::<dyn Cache>::new()
193 .as_default()
194 .with_lifetime(ServiceScope::Singleton)
195 .config();
196 container.with_implementation::<dyn Cache, HybridCache>(hybrid_config);
197
198 container.build()?;
199 Ok(container)
200}
201
202pub fn example_feature_flag_binding() -> Result<IocContainer, CoreError> {
204 let mut container = IocContainer::new();
205
206 let s3_config = AdvancedBindingBuilder::<dyn Storage>::new()
208 .when_feature("cloud-storage")
209 .with_lifetime(ServiceScope::Singleton)
210 .config();
211 container.with_implementation::<dyn Storage, S3Storage>(s3_config);
212
213 let local_config = AdvancedBindingBuilder::<dyn Storage>::new()
215 .when_not_feature("cloud-storage")
216 .with_lifetime(ServiceScope::Singleton)
217 .config();
218 container.with_implementation::<dyn Storage, LocalStorage>(local_config);
219
220 container.build()?;
221 Ok(container)
222}
223
224pub fn example_profile_based_binding() -> Result<IocContainer, CoreError> {
226 let mut container = IocContainer::new();
227
228 let smtp_config = AdvancedBindingBuilder::<dyn EmailService>::new()
230 .named("production_email")
231 .in_profile("production")
232 .with_lifetime(ServiceScope::Singleton)
233 .config();
234 container.with_implementation::<dyn EmailService, SmtpEmailService>(smtp_config);
235
236 let sendgrid_config = AdvancedBindingBuilder::<dyn EmailService>::new()
238 .named("dev_email")
239 .in_profile("development")
240 .with_lifetime(ServiceScope::Singleton)
241 .config();
242 container.with_implementation::<dyn EmailService, SendGridEmailService>(sendgrid_config);
243
244 container.build()?;
245 Ok(container)
246}
247
248pub fn example_custom_condition_binding() -> Result<IocContainer, CoreError> {
250 let mut container = IocContainer::new();
251
252 let redis_config = AdvancedBindingBuilder::<dyn Cache>::new()
254 .named("conditional_cache")
255 .when(|| std::env::var("REDIS_URL").is_ok())
256 .with_lifetime(ServiceScope::Singleton)
257 .config();
258 container.with_implementation::<dyn Cache, RedisCache>(redis_config);
259
260 let memory_config = AdvancedBindingBuilder::<dyn Cache>::new()
262 .named("fallback_cache")
263 .when(|| std::env::var("REDIS_URL").is_err())
264 .with_lifetime(ServiceScope::Singleton)
265 .config();
266 container.with_implementation::<dyn Cache, MemoryCache>(memory_config);
267
268 container.build()?;
269 Ok(container)
270}
271
272pub fn example_factory_patterns() -> Result<IocContainer, CoreError> {
274 let mut container = IocContainer::new();
275
276 container.bind_lazy::<RedisCache, _, _>(|| {
278 println!("Initializing expensive Redis connection...");
279 std::thread::sleep(std::time::Duration::from_millis(10)); RedisCache::default()
281 });
282
283 container.bind_factory::<dyn Cache, _, _>(|| {
285 let cache_type = std::env::var("CACHE_TYPE").unwrap_or_else(|_| "memory".to_string());
286 match cache_type.as_str() {
287 "redis" => Ok(Box::new(RedisCache::default()) as Box<dyn Cache>),
288 "memory" => Ok(Box::new(MemoryCache::default()) as Box<dyn Cache>),
289 _ => Ok(Box::new(HybridCache) as Box<dyn Cache>),
290 }
291 });
292
293 container.build()?;
294 Ok(container)
295}
296
297pub fn example_collection_binding() -> Result<IocContainer, CoreError> {
299 let mut container = IocContainer::new();
300
301 container.bind_collection::<dyn Cache, _>(|collection| {
303 collection
304 .add::<RedisCache>()
305 .add::<MemoryCache>()
306 .add_named::<HybridCache>("hybrid");
307 });
308
309 container.bind_collection::<dyn Storage, _>(|collection| {
311 collection.add::<LocalStorage>().add::<S3Storage>();
312 });
313
314 container.build()?;
315 Ok(container)
316}
317
318pub fn example_complex_conditions() -> Result<IocContainer, CoreError> {
320 let mut container = IocContainer::new();
321
322 let production_redis_config = AdvancedBindingBuilder::<dyn Cache>::new()
324 .named("production_cache")
325 .in_profile("production")
326 .when_env("CACHE_PROVIDER", "redis")
327 .when_feature("high-performance")
328 .when(|| std::env::var("REDIS_CLUSTER_NODES").is_ok())
329 .with_lifetime(ServiceScope::Singleton)
330 .config();
331 container.with_implementation::<dyn Cache, RedisCache>(production_redis_config);
332
333 let staging_config = AdvancedBindingBuilder::<dyn Cache>::new()
335 .named("staging_cache")
336 .in_profile("staging")
337 .when_env("CACHE_PROVIDER", "hybrid")
338 .with_lifetime(ServiceScope::Singleton)
339 .config();
340 container.with_implementation::<dyn Cache, HybridCache>(staging_config);
341
342 let dev_config = AdvancedBindingBuilder::<dyn Cache>::new()
344 .named("dev_cache")
345 .in_profile("development")
346 .config();
347 container.with_implementation::<dyn Cache, MemoryCache>(dev_config);
348
349 container.build()?;
350 Ok(container)
351}
352
353pub fn demonstrate_advanced_binding_features() -> Result<(), CoreError> {
355 println!("=== Advanced Binding Features Demo ===\n");
356
357 println!("1. Environment-based binding:");
359 std::env::set_var("CACHE_PROVIDER", "redis");
360 let container1 = example_environment_based_binding()?;
361 if let Ok(cache) = container1.resolve_named::<RedisCache>("redis") {
362 cache.set("test_key", "test_value".to_string()).ok();
363 }
364 std::env::remove_var("CACHE_PROVIDER");
365
366 println!("\n2. Feature flag binding:");
368 std::env::set_var("FEATURE_CLOUD-STORAGE", "1");
369 let container2 = example_feature_flag_binding()?;
370 if let Ok(storage) = container2.resolve::<S3Storage>() {
371 storage.store("test.txt", b"test data").ok();
372 }
373 std::env::remove_var("FEATURE_CLOUD-STORAGE");
374
375 println!("\n3. Profile-based binding:");
377 std::env::set_var("PROFILE", "production");
378 let container3 = example_profile_based_binding()?;
379 if let Ok(email) = container3.resolve_named::<SmtpEmailService>("production_email") {
380 email
381 .send_email("user@example.com", "Test", "Hello World")
382 .ok();
383 }
384 std::env::remove_var("PROFILE");
385
386 println!("\n4. Factory patterns:");
388 let container4 = example_factory_patterns()?;
389 if let Ok(cache) = container4.resolve::<RedisCache>() {
390 cache.set("lazy_key", "lazy_value".to_string()).ok();
391 }
392
393 println!("\n5. Service statistics:");
395 let stats = container4.get_statistics();
396 println!("Total services: {}", stats.total_services);
397 println!("Singleton services: {}", stats.singleton_services);
398 println!("Cached instances: {}", stats.cached_instances);
399
400 println!("\n6. Service validation:");
402 match container4.validate_all_services() {
403 Ok(()) => println!("All services are valid!"),
404 Err(errors) => println!("Validation errors: {}", errors.len()),
405 }
406
407 println!("\n=== Demo Complete ===");
408 Ok(())
409}
410
411#[cfg(test)]
412mod example_tests {
413 use super::*;
414 use serial_test::serial;
415
416 #[test]
417 #[serial]
418 fn test_environment_based_example() {
419 std::env::set_var("CACHE_PROVIDER", "memory");
420 let result = example_environment_based_binding();
421 assert!(result.is_ok());
422 std::env::remove_var("CACHE_PROVIDER");
423 }
424
425 #[test]
426 fn test_feature_flag_example() {
427 let result = example_feature_flag_binding();
428 assert!(result.is_ok());
429 }
430
431 #[test]
432 #[serial]
433 fn test_profile_based_example() {
434 std::env::set_var("PROFILE", "development");
435 let result = example_profile_based_binding();
436 assert!(result.is_ok());
437 std::env::remove_var("PROFILE");
438 }
439
440 #[test]
441 fn test_factory_patterns_example() {
442 let result = example_factory_patterns();
443 assert!(result.is_ok());
444 }
445
446 #[test]
447 #[serial]
448 fn test_demonstration() {
449 let result = demonstrate_advanced_binding_features();
450 assert!(result.is_ok());
451 }
452}