service-rs - An Async Dependency Injection Container for Rust
An async-first, lightweight dependency injection (DI) container for Rust, inspired by Microsoft.Extensions.DependencyInjection from .NET.
Installation
[]
= { = "https://github.com/SFINXVC/service-rs.git", = "main" }
Compiler support: requires rustc 1.85.0 or higher (uses unstable features: unsize, coerce_unsized)
Note: This library is still in development and is not ready for production use.
Features
- Three service lifetimes: Singleton, Scoped, and Transient
- Async-first design: All service resolution is async using
tokio - Thread-safe: Services are wrapped in
Arc<T>for safe sharing across threads - Automatic dependency injection: Use the
#[derive(Injectable)]macro for automatic constructor injection - Trait object support: Register implementations for trait objects with interface methods
- Scoped services: Create service scopes with scoped lifetime management
Service Lifetimes
- Singleton: One instance created and shared across the entire application
- Scoped: One instance per scope; same instance within a scope, new instance for each scope
- Transient: New instance created every time the service is requested
Basic Example
use ServiceCollection;
use Arc;
async
Using the Injectable Derive Macro
The Injectable derive macro enables automatic dependency injection for structs with dependencies.
use ;
use Arc;
async
Important: All fields in an Injectable struct must be wrapped in Arc<T>.
Scoped Services Example
use ServiceCollection;
use Arc;
async
Trait Object Registration
Register implementations for trait objects using the interface methods:
use ;
use Arc;
;
async
API Overview
ServiceCollection Methods
Factory-based registration:
add_singleton_with_factory<T, F, Fut>(&mut self, factory: F) -> &mut Selfadd_scoped_with_factory<T, F, Fut>(&mut self, factory: F) -> &mut Selfadd_transient_with_factory<T, F, Fut>(&mut self, factory: F) -> &mut Self
Injectable-based registration (requires proc-macro feature):
add_singleton<T: Injectable>(&mut self) -> &mut Selfadd_scoped<T: Injectable>(&mut self) -> &mut Selfadd_transient<T: Injectable>(&mut self) -> &mut Self
Interface registration (requires proc-macro feature):
add_singleton_interface<T: ?Sized, TImpl: Injectable>(&mut self) -> &mut Selfadd_scoped_interface<T: ?Sized, TImpl: Injectable>(&mut self) -> &mut Selfadd_transient_interface<T: ?Sized, TImpl: Injectable>(&mut self) -> &mut Self
Build:
build(self) -> Arc<ServiceProvider>
ServiceProvider Methods
async fn get<T>(&self) -> Result<Arc<T>, ServiceError>fn create_scope(&self) -> Arc<ScopedServiceProvider>
ScopedServiceProvider Methods
async fn get<T>(&self) -> Result<Arc<T>, ServiceError>
Error Handling
The library provides detailed error types via ServiceError:
ServiceNotFound- Service type not registeredServiceAlreadyExists- Service type already registeredServiceResolutionFailed- Failed to resolve serviceServiceInitializationFailed- Factory threw an errorServiceInvalidScope- Attempted to resolve scoped service from root provider
Features
proc-macro(default): Enables theInjectablederive macro and interface registration methods
License
This project is licensed under the MIT License.