use flow_di::{ContainerBuilder, DiResult, ServiceProviderExt};
use std::sync::Arc;
trait ILogger: Send + Sync {
fn log(&self, message: &str);
fn get_logs(&self) -> Vec<String>;
}
trait IRepository: Send + Sync {
fn get_data(&self, id: i32) -> String;
fn save_data(&self, id: i32, data: &str) -> bool;
}
trait IEmailService: Send + Sync {
fn send_email(&self, to: &str, subject: &str, body: &str) -> bool;
}
#[derive(Debug)]
struct ConsoleLogger {
prefix: String,
logs: std::sync::Mutex<Vec<String>>,
}
impl ConsoleLogger {
fn new(prefix: String) -> Self {
Self {
prefix,
logs: std::sync::Mutex::new(Vec::new()),
}
}
}
impl ILogger for ConsoleLogger {
fn log(&self, message: &str) {
let log_message = format!("[{}] {}", self.prefix, message);
println!("{log_message}");
if let Ok(mut logs) = self.logs.lock() {
logs.push(log_message);
}
}
fn get_logs(&self) -> Vec<String> {
self.logs.lock().unwrap().clone()
}
}
struct DatabaseRepository {
logger: Arc<dyn ILogger>,
connection_string: Arc<String>,
}
impl DatabaseRepository {
fn new(logger: Arc<ConsoleLogger>, connection_string: Arc<String>) -> Self {
let logger: Arc<dyn ILogger> = logger;
logger.log("DatabaseRepository initialized");
Self {
logger,
connection_string,
}
}
}
impl IRepository for DatabaseRepository {
fn get_data(&self, id: i32) -> String {
self.logger.log(&format!("Fetching data for ID: {id}"));
format!("Data {id} from {}", self.connection_string)
}
fn save_data(&self, id: i32, data: &str) -> bool {
self.logger
.log(&format!("Saving data for ID: {id} -> {data}"));
true
}
}
struct InMemoryRepository {
logger: Arc<dyn ILogger>,
data: std::sync::Mutex<std::collections::HashMap<i32, String>>,
}
impl InMemoryRepository {
fn new(logger: Arc<ConsoleLogger>) -> Self {
let logger: Arc<dyn ILogger> = logger;
logger.log("InMemoryRepository initialized");
Self {
logger,
data: std::sync::Mutex::new(std::collections::HashMap::new()),
}
}
}
impl IRepository for InMemoryRepository {
fn get_data(&self, id: i32) -> String {
self.logger
.log(&format!("Fetching data from memory for ID: {id}"));
let data = self.data.lock().unwrap();
data.get(&id)
.cloned()
.unwrap_or_else(|| format!("No data for ID: {id}"))
}
fn save_data(&self, id: i32, data: &str) -> bool {
self.logger
.log(&format!("Saving data to memory for ID: {id} -> {data}"));
let mut storage = self.data.lock().unwrap();
storage.insert(id, data.to_string());
true
}
}
struct SmtpEmailService {
logger: Arc<dyn ILogger>,
smtp_server: Arc<String>,
}
impl SmtpEmailService {
fn new(logger: Arc<ConsoleLogger>, smtp_server: Arc<String>) -> Self {
let logger: Arc<dyn ILogger> = logger;
logger.log("SmtpEmailService initialized");
Self {
logger,
smtp_server,
}
}
}
impl IEmailService for SmtpEmailService {
fn send_email(&self, to: &str, subject: &str, body: &str) -> bool {
self.logger.log(&format!(
"Sending email via {} to: {to} | Subject: {subject}",
self.smtp_server
));
println!("Email sent to: {to}\nSubject: {subject}\nBody: {body}");
true
}
}
struct UserService {
repository: Arc<dyn IRepository>,
email_service: Arc<dyn IEmailService>,
logger: Arc<dyn ILogger>,
}
impl UserService {
fn new_concrete(
repository: Arc<DatabaseRepository>,
email_service: Arc<SmtpEmailService>,
logger: Arc<ConsoleLogger>,
) -> Self {
let repository: Arc<dyn IRepository> = repository;
let email_service: Arc<dyn IEmailService> = email_service;
let logger: Arc<dyn ILogger> = logger;
logger.log("UserService initialized");
Self {
repository,
email_service,
logger,
}
}
fn new_memory_concrete(
repository: Arc<InMemoryRepository>,
email_service: Arc<SmtpEmailService>,
logger: Arc<ConsoleLogger>,
) -> Self {
let repository: Arc<dyn IRepository> = repository;
let email_service: Arc<dyn IEmailService> = email_service;
let logger: Arc<dyn ILogger> = logger;
logger.log("UserService initialized");
Self {
repository,
email_service,
logger,
}
}
fn create_user(&self, id: i32, name: &str, email: &str) -> bool {
self.logger.log(&format!(
"Creating user: ID={id}, Name={name}, Email={email}"
));
let user_data = format!("{{\"name\":\"{name}\",\"email\":\"{email}\"}}");
if self.repository.save_data(id, &user_data) {
let subject = "Welcome!";
let body = &format!("Hello {name}, welcome to our service!");
self.email_service.send_email(email, subject, body);
self.logger.log("User created successfully");
true
} else {
self.logger.log("Failed to create user");
false
}
}
fn get_user(&self, id: i32) -> Option<String> {
self.logger.log(&format!("Getting user with ID: {id}"));
let data = self.repository.get_data(id);
if data.starts_with("No data") {
None
} else {
Some(data)
}
}
}
fn main() -> DiResult<()> {
println!("=== Flow-DI Basic Usage Example ===\n");
let provider = ContainerBuilder::new()
.add_instance("postgresql://localhost:5432/myapp".to_string())
.add_named_instance("smtp_server", "smtp.gmail.com:587".to_string())
.add_singleton_simple::<ConsoleLogger, ConsoleLogger>(|| {
ConsoleLogger::new("APP".to_string())
})
.add_named_singleton_simple::<ConsoleLogger, ConsoleLogger>("file_logger", || {
ConsoleLogger::new("FILE".to_string())
})
.add_scoped::<DatabaseRepository, DatabaseRepository>(|provider| {
let logger = provider.get_required_service::<ConsoleLogger>()?;
let connection_string = provider.get_required_service::<String>()?;
Ok(DatabaseRepository::new(logger, connection_string))
})
.add_named_scoped::<InMemoryRepository, InMemoryRepository>("memory", |provider| {
let logger = provider.get_required_service::<ConsoleLogger>()?;
Ok(InMemoryRepository::new(logger))
})
.add_singleton::<SmtpEmailService, SmtpEmailService>(|provider| {
let logger = provider.get_required_service::<ConsoleLogger>()?;
let smtp_server = provider.get_required_keyed_service::<String>("smtp_server")?;
Ok(SmtpEmailService::new(logger, smtp_server))
})
.add_transient::<UserService, UserService>(|provider| {
let repository = provider.get_required_service::<DatabaseRepository>()?;
let email_service = provider.get_required_service::<SmtpEmailService>()?;
let logger = provider.get_required_service::<ConsoleLogger>()?;
Ok(UserService::new_concrete(repository, email_service, logger))
})
.add_named_transient::<UserService, UserService>("memory_user_service", |provider| {
let repository = provider.get_required_keyed_service::<InMemoryRepository>("memory")?;
let email_service = provider.get_required_service::<SmtpEmailService>()?;
let logger = provider.get_required_keyed_service::<ConsoleLogger>("file_logger")?;
Ok(UserService::new_memory_concrete(
repository,
email_service,
logger,
))
})
.build();
println!("1. 基础服务解析");
let logger = provider.get_required_service::<ConsoleLogger>()?;
logger.log("Application started");
println!("\n2. 单例行为演示");
let logger1 = provider.get_required_service::<ConsoleLogger>()?;
let logger2 = provider.get_required_service::<ConsoleLogger>()?;
println!(
"Logger instances are same: {}",
Arc::ptr_eq(&logger1, &logger2)
);
println!("\n3. 作用域服务演示");
{
let mut scope1 = provider.create_scope()?;
let repo1_a = scope1.get_required_service::<DatabaseRepository>()?;
let repo1_b = scope1.get_required_service::<DatabaseRepository>()?;
println!(
"Scope1 - Repository instances are same: {}",
Arc::ptr_eq(&repo1_a, &repo1_b)
);
let mut scope2 = provider.create_scope()?;
let repo2 = scope2.get_required_service::<DatabaseRepository>()?;
println!(
"Different scopes - Repository instances are same: {}",
Arc::ptr_eq(&repo1_a, &repo2)
);
scope1.dispose();
scope2.dispose();
}
println!("\n4. 瞬时服务演示");
let mut scope = provider.create_scope()?;
let user_service1 = scope.get_required_service::<UserService>()?;
let user_service2 = scope.get_required_service::<UserService>()?;
println!(
"Transient services are same: {}",
Arc::ptr_eq(&user_service1, &user_service2)
);
println!("\n5. 业务逻辑演示");
user_service1.create_user(1, "Alice", "alice@example.com");
user_service1.create_user(2, "Bob", "bob@example.com");
if let Some(user_data) = user_service1.get_user(1) {
println!("Retrieved user: {user_data}");
}
println!("\n6. 命名服务演示");
let memory_user_service =
scope.get_required_keyed_service::<UserService>("memory_user_service")?;
memory_user_service.create_user(10, "Charlie", "charlie@example.com");
if let Some(user_data) = memory_user_service.get_user(10) {
println!("Retrieved user from memory: {user_data}");
} else {
println!("User not found in memory repository");
}
println!("\n7. 服务集合演示");
let all_repositories = scope.get_services::<DatabaseRepository>()?;
println!(
"Total repository implementations: {}",
all_repositories.len()
);
println!("\n8. 日志记录");
let main_logger = scope.get_required_service::<ConsoleLogger>()?;
let logs = main_logger.get_logs();
println!("Total log entries: {}", logs.len());
for (i, log) in logs.iter().take(5).enumerate() {
println!(" {}. {log}", i + 1);
}
if logs.len() > 5 {
println!(" ... and {} more", logs.len() - 5);
}
scope.dispose();
println!("\n=== Example Completed ===");
Ok(())
}