Skip to content

Desiders/froodi

Repository files navigation

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

About

An ergonomic Rust IoC container

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Contributors 3

  •  
  •  
  •