1 unstable release
Uses new Rust 2024
new 0.1.0 | Apr 23, 2025 |
---|
#1028 in Algorithms
Used in 2 crates
13KB
164 lines
Illuminate Container
A lightweight dependency injection container for Rust, designed to manage services, factories, and singletons with type-safe bindings. This container supports binding factories, registering singletons, and resolving instances, making it suitable for building modular and testable applications.
Features
- Type-Safe Bindings: Bind factories to create instances of specific types.
- Singleton Support: Register singletons to ensure a single instance is reused.
- Transient Factories: Create new instances on each resolution.
- Service Providers: Register and boot service providers for modular configuration.
- Dynamic Resolution: Resolve instances by type using
TypeId
.
Usage
The Container
struct is the core of the library. Below are examples demonstrating how to use its key functionalities.
Setup
Create a new Container
instance:
use container::Container;
let mut container = Container::new();
Binding a Factory
Bind a factory to create new instances of a type (transient instances):
#[derive(Debug, PartialEq)]
struct TestService {
value: i32,
}
impl TestService {
fn new(value: i32) -> Self {
Self { value }
}
}
container.bind(TestService::new(0), |_: &dyn Contract| TestService::new(42));
Resolve a transient instance:
let instance = container.transient(TypeId::of::<TestService>()).unwrap();
let service = instance.downcast_ref::<TestService>().unwrap();
assert_eq!(service.value, 42);
Registering a Singleton
Register a singleton instance to ensure only one instance is created and reused:
let type_id = TypeId::of::<TestService>();
container.singleton(type_id, Box::new(TestService::new(42)));
let instance = container.resolve_any(type_id).unwrap();
let service = instance.downcast_ref::<TestService>().unwrap();
assert_eq!(service.value, 42);
// Subsequent resolutions return the same instance
let instance2 = container.resolve_any(type_id).unwrap();
assert_eq!(
std::ptr::eq(
instance.downcast_ref::<TestService>().unwrap(),
instance2.downcast_ref::<TestService>().unwrap()
),
true
);
Using a Singleton Factory
Register a singleton via a factory, which is executed once to create the instance:
let type_id = TypeId::of::<TestService>();
let factory = |_: &dyn Contract| -> Box<dyn Any> { Box::new(TestService::new(42)) };
container.singleton_factory(type_id, Box::new(factory));
let instance = container.resolve_any(type_id).unwrap();
let service = instance.downcast_ref::<TestService>().unwrap();
assert_eq!(service.value, 42);
// Same instance is reused
let instance2 = container.resolve_any(type_id).unwrap();
assert_eq!(
std::ptr::eq(
instance.downcast_ref::<TestService>().unwrap(),
instance2.downcast_ref::<TestService>().unwrap()
),
true
);
Registering Service Providers
Service providers allow modular configuration of the container:
use illuminate_contracts::support::ServiceProvider;
struct MyProvider;
impl ServiceProvider for MyProvider {
fn register(&mut self, container: &mut dyn Contract) {
container.bind_any(TypeId::of::<TestService>(), Box::new(TestService::new(100)));
}
fn boot(&mut self, _container: &mut dyn Contract) {
// Perform boot-time initialization
}
}
container.register_provider(Box::new(MyProvider));
container.boot();
Notes
- Singletons are stored separately from transient services to ensure proper instance management.
- The container uses
TypeId
for type-safe resolution, so ensure types are unique and correctly registered. - Factories are executed each time for transient resolutions but only once for singleton factories.
Testing
The library includes a comprehensive test suite to verify the behavior of bindings, singletons, and service providers. To run the tests:
cargo test
License
This project is licensed under the MIT License.
Dependencies
~4KB