Skip to content

A simple and lightweight dependency injection container for Rust.

Notifications You must be signed in to change notification settings

ipconfiger/ru-di

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ru-di

A simple and lightweight dependency injection container for Rust.

Crates.io Documentation License

Features

  • Simple and lightweight
  • Thread-safe
  • Support for both transient and singleton services
  • Both sync (Di) and async (TkDi) containers
  • No runtime overhead
  • Zero dependencies for sync container

Installation

Add this to your Cargo.toml:

[dependencies]
ru-di = "0.2"

Usage

Synchronous Container (Di)

The Di container provides dependency injection for synchronous code.

use ru_di::Di;

// Define your services
struct Database {
    port: u16,
}

struct AppService {
    db: Database,
}

// Register services
Di::register::<Database, _>(|_| Database { port: 3306 });
Di::register::<AppService, _>(|di| {
    let db = di.get_inner::<Database>().unwrap();
    AppService { db: db.clone() }
});

// Get service instance
let app = Di::get::<AppService>().unwrap();
assert_eq!(app.db.port, 3306);

Singleton Services

use ru_di::Di;

#[derive(Debug, PartialEq)]
struct Configuration {
    port: u16,
}

// Register a singleton
Di::register_single(Configuration { port: 8080 });

// Get singleton instance
if let Some(mut config) = Di::get_single::<Configuration>() {
    let mut config = config.get_mut().unwrap();
    assert_eq!(config.port, 8080);
    config.port = 8081;
}

// The change persists
if let Some(mut config) = Di::get_single::<Configuration>() {
    let config = config.get_mut().unwrap();
    assert_eq!(config.port, 8081);
}

Asynchronous Container (TkDi)

The TkDi container provides dependency injection for async/await code with Tokio.

use ru_di::TkDi;

#[derive(Clone)]
struct Database {
    port: u16,
}

struct AppService {
    db: Database,
}

// Register services (factory receives &TkDi parameter)
TkDi::register(|_di| Database { port: 3306 }).await;

// Register services with dependencies
TkDi::register(|_di| {
    AppService { db: Database { port: 3307 } }
}).await;

// Get service instance
let app = TkDi::get::<AppService>().await.unwrap();
assert_eq!(app.db.port, 3307);

// Register and use singletons
TkDi::register_single(Configuration { port: 8080 }).await;

if let Some(mut config) = TkDi::get_single::<Configuration>().await {
    let mut config = config.get_mut().await;
    assert_eq!(config.port, 8080);
    config.port = 8081;
}

API Documentation

Synchronous Container (Di)

Registering Services

  • Di::register<T, F>(factory: F) - Register a transient service
    • T: Service type (must be 'static + Send + Sync)
    • F: Factory closure Fn(&Di) -> T
  • Di::register_single<T>(instance: T) - Register a singleton service

Getting Services

  • Di::get<T>() -> Result<T, DiError> - Get a transient service instance
  • Di::get_single<T>() -> Option<SingleRef<T>> - Get a singleton service instance
  • SingleRef<T>::get(&self) -> Result<RwLockReadGuard<'_, T>, DiError> - Get read access
  • SingleRef<T>::get_mut(&mut self) -> Result<RwLockWriteGuard<'_, T>, DiError> - Get write access

Asynchronous Container (TkDi)

Registering Services

  • TkDi::register<T, F>(factory: F) - Register a transient service
    • T: Service type (must be 'static + Send + Sync)
    • F: Factory closure Fn(&TkDi) -> T
  • TkDi::register_single<T>(instance: T) - Register a singleton service

Getting Services

  • TkDi::get<T>() -> Result<T, DiError> - Get a transient service instance
  • TkDi::get_single<T>() -> Option<SingleAsyncRef<T>> - Get a singleton service instance
  • SingleAsyncRef<T>::get(&self) - Get read access (returns RwLockReadGuard)
  • SingleAsyncRef<T>::get_mut(&mut self) - Get write access (returns RwLockWriteGuard)

Error Types

  • DiError::ProviderNotFound - Service provider not registered
  • DiError::TypeMismatch - Type conversion failed
  • DiError::LockError - Lock acquisition failed

Thread Safety

All operations are thread-safe:

  • Di uses Arc, Mutex, and RwLock from std
  • TkDi uses Arc, TokioMutex, and TokioRwLock for async compatibility

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

A simple and lightweight dependency injection container for Rust.

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages