Skip to content

Desiders/froodi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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.
  • 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 use Rc instead of Arc and off Send/Sync requirements

Community

Telegram

Quickstart

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

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

  •  
  •  
  •