Froodi is a lightweight, ergonomic Inversion of Control (IoC) container for Rust that helps manage dependencies with clear scoping and lifecycle management in a simple manner
- Scoping: Any object can have a lifespan for the entire app, a single request, or even more fractionally
- Finalization: Some dependencies, like database connections, need not only to be created but also carefully released. Many frameworks lack this essential feature.
- Ergonomic: Simple API
- Speed: Dependency resolving as fast as the speed of light thanks to the Rust
- Integration: The popular frameworks for building applications is supported out of the box (axum, dptree)
- Safe: 100% safe Rust (no unsafe used)
- Thread safe: Thread safety enabled by default (
thread_safe
feature) and can be disabled to useRc
instead ofArc
and offSend
/Sync
requirements
- 🇺🇸 🇷🇺 @froodi_di
use froodi::{
Container,
DefaultScope::{App, Request},
Inject, InjectTransient, InstantiatorResult, RegistryBuilder, instance,
};
#[derive(Default, Clone)]
struct Config {
_host: &'static str,
_port: i16,
_user: &'static str,
_password: &'static str,
_db: &'static str,
}
trait UserRepo {
fn create_user(&self);
}
struct PostgresUserRepo;
impl UserRepo for PostgresUserRepo {
fn create_user(&self) {
todo!()
}
}
struct CreateUser<R> {
repo: R,
}
impl<R: UserRepo> CreateUser<R> {
fn handle(&self) {
self.repo.create_user();
}
}
fn init_container(config: Config) -> Container {
#[allow(clippy::unnecessary_wraps)]
fn create_user<R>(InjectTransient(repo): InjectTransient<R>) -> InstantiatorResult<CreateUser<R>> {
Ok(CreateUser { repo })
}
let registry = RegistryBuilder::new()
.provide(instance(config), App)
.provide(|_config: Inject<Config>| Ok(PostgresUserRepo), Request)
.provide(create_user::<PostgresUserRepo>, Request);
Container::new(registry)
}
fn main() {
let app_container = init_container(Config::default());
let request_container = app_container.clone().enter_build().unwrap();
let interactor = request_container.get_transient::<CreateUser<PostgresUserRepo>>().unwrap();
interactor.handle();
let _config = request_container.get::<Config>().unwrap();
request_container.close();
app_container.close();
}
- Sync provide. This example shows how to provide sync dependencies.
- Async provide. This example shows how to provide async sync dependencies.
- Sync finalizer. This example shows how to add sync finalizers.
- Async finalizer. This example shows how to add async finalizers.
- Boxed dyn provide. This example shows how to provide boxed dyn dependencies.
- Axum. This example shows how to integrate the framework with Axum library.
- Dptree. This example shows how to integrate the framework with Dptree library.
- Telers. This example shows how to integrate the framework with Telers framework.
You may consider checking out this directory for examples.
Contributions are welcome!