froodi 1.0.0-beta.17

An ergonomic Rust IoC container
Documentation

Froodi - an ergonomic Rust IoC container

Crates.io

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

Features

  • 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.
  • Modular registries: You can register factories in different registries and combine them to avoid one large macros.
  • Auto-Registration: There way to use auto registration for factories
  • Ergonomic: Simple API
  • Safe: 100% safe Rust (no unsafe used)
  • Thread safe: Thread safety enabled by default (thread_safe feature) and can be disabled to use Rc instead of Arc and off Send/Sync requirements
  • 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)

Community

Telegram

Quickstart

use froodi::{
    Container,
    DefaultScope::{App, Request},
    Inject, InjectTransient, InstantiatorResult, instance, registry,
};

#[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 })
    }

    Container::new(registry! {
        provide(App, instance(config)),
        scope(Request) [
            provide(|_config: Inject<Config>| Ok(PostgresUserRepo)),
            provide(create_user::<PostgresUserRepo>),
        ],
    })
}

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();
}

Examples

  • 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.

Contributing

Contributions are welcome!

License

Apache License, Version 2.0