Skip to main content

Crate rust_dix

Crate rust_dix 

Source
Expand description

LRDI — Rust Dependency Injection Framework

A dependency injection container for Rust inspired by Microsoft.Extensions.DependencyInjection (MEDI).

§Quick start

use rust_dix::*;
use std::sync::Arc;

// Trait-based interface (recommended)
trait ILogger: Send + Sync {
    fn log(&self, msg: &str);
}

struct ConsoleLogger;
impl ILogger for ConsoleLogger {
    fn log(&self, msg: &str) { println!("[LOG] {}", msg); }
}

// Register as trait interface
let provider = ServiceCollection::new()
    .singleton::<dyn ILogger>(|_| Arc::new(ConsoleLogger))
    .build()
    .unwrap();

// Resolve as trait
let logger: Arc<dyn ILogger> = provider.get().unwrap();
logger.log("Hello");

§Keyed services (strategy pattern)

use rust_dix::*;
use std::sync::Arc;

trait Strategy: Send + Sync { fn execute(&self) -> &'static str; }

struct FastStrategy;
impl Strategy for FastStrategy { fn execute(&self) -> &'static str { "fast" } }

struct SafeStrategy;
impl Strategy for SafeStrategy { fn execute(&self) -> &'static str { "safe" } }

let provider = ServiceCollection::new()
    .keyed_singleton::<dyn Strategy>("fast", |_| Arc::new(FastStrategy))
    .keyed_singleton::<dyn Strategy>("safe", |_| Arc::new(SafeStrategy))
    .build()
    .unwrap();

let fast: Arc<dyn Strategy> = provider.get_keyed("fast").unwrap();
assert_eq!(fast.execute(), "fast");

§Build-time validation

LRDI validates dependencies during build() to catch errors early:

// Circular dependency detection — factories resolve deps via `get_any`
// (the `get::<T>()` method requires `Self: Sized` and cannot be called
// on `&dyn IServiceResolver`).
let result = ServiceCollection::new()
    .singleton(|r| {
        let _b = r.get_any(std::any::type_name::<B>());  // A depends on B
        Arc::new(A)
    })
    .singleton(|r| {
        let _a = r.get_any(std::any::type_name::<A>());  // B depends on A → CIRCULAR!
        Arc::new(B)
    })
    .build();

assert!(result.is_err());
if let Err(RdiError::CircularDependency(cycle)) = result {
    println!("Circular dependency detected: {}", cycle);
}

§Async support

For services that require async initialization (e.g., database connections, remote config loading), use build_async() and the async_* registration methods. build_async() returns Arc<ServiceProvider> so that provider_arc() is available for async resolution:

use rust_dix::*;
use std::sync::Arc;

struct DbPool { conn: String }

async fn connect_to_db() -> DbPool {
    // async connection setup...
    DbPool { conn: "connected".into() }
}

let provider = ServiceCollection::new()
    .async_singleton(|_| Box::pin(async {
        Arc::new(connect_to_db().await)
    }))
    .build_async()
    .await
    .unwrap();

let pool: Arc<DbPool> = provider.get_async().await.unwrap();

§Features

  • Three lifetimes: Singleton, Scoped, Transient
  • Keyed services: multiple implementations of the same trait by key
    • keyed_singleton(key, factory) — shared globally
    • keyed_scoped(key, factory) — shared within scope
    • keyed_transient(key, factory) — new instance each time
  • Constructor injection: #[derive(Inject)] on structs
  • Attribute-based auto-registration: #[rust_dix::inject] on structs or trait impls
  • Compile-time module scanning: #[rust_dix::module] collects register!() declarations
  • Cross-DLL support: named service registry for cdylib plugins
  • Layered containers: child-first resolution via ServiceProviderWrapper
  • Build-time validation: circular dependency detection during build()

§Crate layout

ModuleDescription
ServiceCollectionRegister services with a builder API
ServiceProviderThe root DI container
Scope / ServiceScopeScoped container (one per scope)
IServiceResolverResolution trait (implemented by ServiceProvider & Scope)
ServiceProviderWrapperChild-first layered container
ServiceLifetimeEnum: Singleton, Scoped, Transient
IProviderUnified trait for resolution + named registry
RdiErrorError types (includes CircularDependency)

§Proc-macros

  • #[derive(Inject)] — auto-generates constructor injection code
  • #[rust_dix::inject] — auto-registration on structs or trait impls
  • #[rust_dix::module] — compile-time module scanning
  • rust_dix::register!(...) — declare services inside #[rust_dix::module]

Re-exports§

pub use collection::ServiceCollection;
pub use provider::ServiceProvider;
pub use entry::ServiceDescriptor;
pub use entry::ServiceLifetime;
pub use entry::IServiceResolver;
pub use scope::Scope;
pub use scope::Scope as ServiceScope;
pub use scope::ScopeFactory;
pub use entry::ServiceEntry;
pub use entry::ServiceFactory;
pub use wrapper::ServiceProviderWrapper;
pub use bridge::IProvider;
pub use error::RdiError;
pub use registration::ServiceRegistration;

Modules§

bridge
Unified provider trait for service resolution and named registry access.
collection
entry
error
provider
registration
scope
wrapper

Macros§

register

Attribute Macros§

inject
module

Derive Macros§

Inject