use crate::container::{IocContainerBuilder, ServiceBinder};
use crate::errors::CoreError;
use std::sync::Arc;
pub trait UserRepository: Send + Sync {
fn find_by_id(&self, id: u32) -> Option<String>;
fn create(&self, name: &str) -> Result<u32, String>;
}
#[derive(Default)]
pub struct PostgresUserRepository {
connection_string: String,
}
unsafe impl Send for PostgresUserRepository {}
unsafe impl Sync for PostgresUserRepository {}
impl PostgresUserRepository {
pub fn new(connection_string: String) -> Self {
Self { connection_string }
}
}
impl UserRepository for PostgresUserRepository {
fn find_by_id(&self, id: u32) -> Option<String> {
Some(format!("User {} from {}", id, self.connection_string))
}
fn create(&self, _name: &str) -> Result<u32, String> {
Ok(42) }
}
#[derive(Default)]
pub struct UserService {
}
unsafe impl Send for UserService {}
unsafe impl Sync for UserService {}
impl UserService {
pub fn get_user(&self, id: u32) -> Option<String> {
Some(format!("User {}", id))
}
}
pub fn basic_container_example() -> Result<(), CoreError> {
let mut builder = IocContainerBuilder::new();
builder
.bind_singleton::<PostgresUserRepository, PostgresUserRepository>()
.bind::<UserService, UserService>();
let container = builder.build()?;
let repo = container.resolve::<PostgresUserRepository>()?;
let user = repo.find_by_id(1);
assert!(user.is_some());
let service = container.resolve::<UserService>()?;
let user_data = service.get_user(1);
assert!(user_data.is_some());
Ok(())
}
pub fn named_services_example() -> Result<(), CoreError> {
let mut builder = IocContainerBuilder::new();
builder
.bind_named::<PostgresUserRepository, PostgresUserRepository>("primary")
.bind_named::<PostgresUserRepository, PostgresUserRepository>("backup");
let container = builder.build()?;
let primary_repo = container.resolve_named::<PostgresUserRepository>("primary")?;
let backup_repo = container.resolve_named::<PostgresUserRepository>("backup")?;
assert!(primary_repo.find_by_id(1).is_some());
assert!(backup_repo.find_by_id(1).is_some());
Ok(())
}
pub fn factory_services_example() -> Result<(), CoreError> {
let mut builder = IocContainerBuilder::new();
builder.bind_factory::<PostgresUserRepository, _, _>(|| {
Ok(PostgresUserRepository::new(
"postgres://localhost/db".to_string(),
))
});
let container = builder.build()?;
let repo = container.resolve::<PostgresUserRepository>()?;
assert!(repo.find_by_id(1).is_some());
Ok(())
}
pub fn lifetime_example() -> Result<(), CoreError> {
let mut builder = IocContainerBuilder::new();
builder.bind_singleton::<UserService, UserService>();
builder.bind_transient::<PostgresUserRepository, PostgresUserRepository>();
let container = builder.build()?;
let service1 = container.resolve::<UserService>()?;
let service2 = container.resolve::<UserService>()?;
assert!(Arc::ptr_eq(&service1, &service2));
let repo1 = container.resolve::<PostgresUserRepository>()?;
let repo2 = container.resolve::<PostgresUserRepository>()?;
assert!(!Arc::ptr_eq(&repo1, &repo2));
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_container_example() {
basic_container_example().unwrap();
}
#[test]
fn test_named_services_example() {
named_services_example().unwrap();
}
#[test]
fn test_factory_services_example() {
factory_services_example().unwrap();
}
#[test]
fn test_lifetime_example() {
lifetime_example().unwrap();
}
}