pub struct Container { /* private fields */ }Expand description
The Dependency Injection (DI) Container.
This is the core registry for all providers, services, and configuration in a NestForge application. It mimics the behavior of the NestJS container but is adapted for Rust’s ownership and thread-safety models.
§Core Features
- Singleton Registry: By default, registered services are singletons (Arc
). - Thread Safety: Uses
RwLockto allow concurrent reads (resolving) and exclusive writes (registering). - Type-Based Resolution: Services are stored and retrieved by their
TypeId. - Scoped & Transient: Supports request-scoped and transient factories for more complex lifecycles.
Implementations§
Source§impl Container
impl Container
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new, empty container.
This is equivalent to Container::default().
Sourcepub fn scoped(&self) -> Self
pub fn scoped(&self) -> Self
Creates a “scoped” child container.
A scoped container shares the underlying singleton registry (inner) with its parent
but has its own empty overrides map.
This is used during HTTP requests to create a context where request-scoped providers can be cached for the duration of that single request without affecting the global state.
Sourcepub fn register<T>(&self, value: T) -> Result<(), ContainerError>
pub fn register<T>(&self, value: T) -> Result<(), ContainerError>
Registers a value (singleton) into the container.
The value must be thread-safe (Send + Sync) and 'static.
§Example
container.register(AppConfig::default())?;Sourcepub fn replace<T>(&self, value: T) -> Result<(), ContainerError>
pub fn replace<T>(&self, value: T) -> Result<(), ContainerError>
Replaces an existing registration with a new value.
Unlike register, this will not error if the type is already present.
It effectively updates the singleton instance.
Sourcepub fn override_value<T>(&self, value: T) -> Result<(), ContainerError>
pub fn override_value<T>(&self, value: T) -> Result<(), ContainerError>
Overrides a value in the current scope.
If called on a global container, it works like replace but stores the value
in the overrides map, which takes precedence over inner.
If called on a scoped() container, the override only exists for that scope.
Sourcepub fn is_type_registered_name(
&self,
type_name: &'static str,
) -> Result<bool, ContainerError>
pub fn is_type_registered_name( &self, type_name: &'static str, ) -> Result<bool, ContainerError>
Checks if a type with the given name is registered.
This relies on std::any::type_name matching what was stored.
Sourcepub fn register_request_factory<T, F>(
&self,
factory: F,
) -> Result<(), ContainerError>
pub fn register_request_factory<T, F>( &self, factory: F, ) -> Result<(), ContainerError>
Registers a factory for request-scoped providers.
A request-scoped provider is created once per scoped() container (i.e., once per request)
and then cached within that scope.
Sourcepub fn register_transient_factory<T, F>(
&self,
factory: F,
) -> Result<(), ContainerError>
pub fn register_transient_factory<T, F>( &self, factory: F, ) -> Result<(), ContainerError>
Registers a factory for transient providers.
A transient provider is created anew every single time it is resolved. It is never cached.
Sourcepub fn resolve<T>(&self) -> Result<Arc<T>, ContainerError>
pub fn resolve<T>(&self) -> Result<Arc<T>, ContainerError>
Resolves (retrieves) a registered provider.
The search order is:
- Overrides (scoped instances)
- Singletons (global instances)
- Request-scoped factories (create and cache in overrides if found)
- Transient factories (create new instance)
Returns an Arc<T> so the service can be cheaply shared.