Rudi - an out-of-the-box dependency injection framework for Rust.

Related tags

Command-line rudi
Overview

Rudi

Crates.io version docs.rs docs

Rudi - an out-of-the-box dependency injection framework for Rust.

use rudi::{Context, Singleton, Transient};

// Register `fn(cx) -> A { A }` as the constructor for `A`
#[derive(Debug)]
#[Transient]
struct A;

#[derive(Debug)]
struct B(A);

// Register `fn(cx) -> B { B::new(cx.resolve::<A>()) }` as the constructor for `B`
#[Transient]
impl B {
    fn new(a: A) -> B {
        B(a)
    }
}

// Register `fn(cx) -> C { C::B(cx.resolve::<B>()) }` as the constructor for `C`
#[allow(dead_code)]
#[Transient]
enum C {
    A(A),

    #[di]
    B(B),
}

// Register `fn(cx) -> () { Run(cx.resolve::<B>()) }` as the constructor for `()`
#[Singleton]
fn Run(b: B, c: C) {
    println!("{:?}", b);
    assert!(matches!(c, C::B(_)));
}

fn main() {
    // Automatically register all types and functions with the `#[Singleton]` or `#[Transient]` attribute.
    let mut cx = Context::auto_register();

    // Get an instance of `()` from the `Context`, which will call the `Run` function.
    // This is equivalent to `cx.resolve::<()>();`
    cx.resolve()
}

Features

  • Two lifetimes: singleton and transient.
  • Async functions and async constructors.
  • Attribute macros can be used on struct, enum, impl block and function.
  • Manual and automatic registration (thanks to inventory).
  • Easy binding of trait implementations and trait objects.
  • Distinguishing different instances with types and names.
  • Generics (but must be monomorphized and manually registered)

More complex example

use std::{fmt::Debug, rc::Rc};

use rudi::{Context, Singleton, Transient};

// Register `async fn(cx) -> i32 { 42 }` as the constructor for `i32`,
// and specify the name of the instance of this `i32` type as `"number"`.
#[Singleton(name = "number")]
async fn Number() -> i32 {
    42
}

// Register `async fn(cx) -> Foo { Foo { number: cx.resolve_with_name_async("number").await } }`
// as the constructor for `Foo`, and specify the name of the instance of this `Foo` type as `"foo"`.
#[derive(Debug, Clone)]
#[Singleton(async, name = "foo")]
struct Foo {
    #[di(name = "number")]
    number: i32,
}

#[derive(Debug)]
struct Bar(Foo);

impl Bar {
    fn into_debug(self) -> Rc<dyn Debug> {
        Rc::new(self)
    }
}

// Register `async fn(cx) -> Bar { Bar::new(cx.resolve_with_name_async("foo").await).await }`
// as the constructor for `Bar`.
//
// Bind the implementation of the `Debug` trait and the trait object of the `Debug` trait,
// it will register `asycn fn(cx) -> Rc<dyn Debug> { Bar::into_debug(cx.resolve_async().await) }`
// as the constructor for `Rc<dyn Debug>`.
#[Transient(binds = [Self::into_debug])]
impl Bar {
    async fn new(#[di(name = "foo")] f: Foo) -> Bar {
        Bar(f)
    }
}

#[Singleton]
async fn Run(bar: Bar, debug: Rc<dyn Debug>, #[di(name = "foo")] f: Foo) {
    println!("{:?}", bar);
    assert_eq!(format!("{:?}", bar), format!("{:?}", debug));
    assert_eq!(format!("{:?}", bar.0.number), format!("{:?}", f.number));
}

#[tokio::main]
async fn main() {
    let mut cx = Context::auto_register();

    cx.resolve_async().await
}

More examples can be found in the examples and tests directories.

Credits

  • Koin: This project's API design and test cases were inspired by Koin.
  • inventory: This project uses inventory to implement automatic registration, making Rust's automatic registration very simple.

Contributing

Thanks for your help improving the project! We are so happy to have you!

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

You might also like...
A truly zero-dependency crate providing quick, easy, reliable, and scalable access to the name "jordin"

jordin Finally! A truly zero-dependency crate providing quick, easy, reliable, and scalable access to the name "jordin". Additionally, this one-of-a-k

Track and query Cargo dependency graphs.

cargo-guppy: track and query dependency graphs This repository contains the source code for: guppy: a library for performing queries on Cargo dependen

A lightweight, zero-dependency struct diffing library which allows changed fields to be collected and applied

structdiff A lightweight, zero-dependency struct diffing library which allows changed fields to be collected and applied. Derive Difference on a struc

Generate a dependency list to thank them on README.

thanks-dependencies This generates list of dependencies. I think it's better to publish dependencies explicitly on documentation. Of course users can

A high-performance WebSocket integration library for streaming public market data. Used as a key dependency of the `barter-rs` project.

Barter-Data A high-performance WebSocket integration library for streaming public market data from leading cryptocurrency exchanges - batteries includ

Basic template for an out-of-tree Linux kernel module written in Rust.

Rust out-of-tree module This is a basic template for an out-of-tree Linux kernel module written in Rust. Please note that: The Rust support is experim

A utility written in Rust for dumping binary information out of Mach-O files inspired by objdump

Mach-O Dump (macho-dump) An objdump like tool for exploring and manipulating Mach-O files. Note: This project is in an early stage and most of the fea

Testing out if Rust can be used for a normal Data Engineering Pipeline.

RustForDataPipelines Testing out if Rust can be used for a normal Data Engineering Pipeline. Check out the full blog post here. https://www.confession

Need a powerful and simple library to work with arithmetic progressions in Rust? You should definitively try out ariprog!

Ariprog I had a test (03/2024) on arithmetic progressions, so I decided to create a library to study math. Taking advantage of the fact that I was stu

Comments
  • Support for dependency's field injection.

    Support for dependency's field injection.

    When inject a specific field from a struct, for example, I think it would be better to code like this:

    // Register async function and specify name
    #[Singleton(name = "number")]
    async fn Number() -> u32 {
        42
    }
    
    #[derive(Debug, Clone)]
    #[Singleton(name = "config")] // Register async constructor and specify name
    struct Config{
        #[di(name = "number")] // Specify the name of the dependency
        max_user: u32,
    }
    
    #[derive(Debug)]
    struct Bar(i32);
    
    impl Bar {
        fn into_debug(self) -> Rc<dyn Debug> {
            Rc::new(self)
        }
    }
    
    #[Transient(binds = [Self::into_debug])] // Bind the implementation of the `Debug` trait and the trait object of the `Debug` trait
    impl Bar {
        async fn new(#[di(name = "config.max_user")] max_user: u32) -> Bar { // Register async constructor
            Bar(max_user)
        }
    }
    
    opened by zooeywm 3
  • Parentheses should be omitted when just use #[di()] in struct field.

    Parentheses should be omitted when just use #[di()] in struct field.

    In current version, If I need to inject a i32 for a struct field without specified dependency name, I need to type #[di()]

    Here's my usecase:

    #[Singleton]
    async fn Number() -> i32 {
        452
    }
    
    #[Singleton(async)]
    struct Config {
        #[di()]
        number: i32,
        #[di(default = 123)]
        test: u32,
    }
    

    It would be better to write it just as #[di]. Meanwhile, if I don't need to specify test to 123, I can just remove the #[di(default = 123)], and derive Default for Config, tell the provider to use u32::default() for initializing this field

    The better syntax may be like this:

    #[Singleton]
    async fn Number() -> i32 {
        452
    }
    
    #[derive(Default)]
    #[Singleton(async)]
    struct Config {
        #[di]
        number: i32,
        test: u32,
    }
    
    opened by zooeywm 1
Releases(v0.3.1)
Owner
ZihanType
ZihanType
Rust Server Components. JSX-like syntax and async out of the box.

RSCx - Rust Server Components RSCx is a server-side HTML rendering engine library with a neat developer experience and great performance. Features: al

Antonio Pitasi 21 Sep 19, 2023
Rusty Shellcode Reflective DLL Injection (sRDI) - A small reflective loader in Rust 4KB in size for generating position-independent code (PIC) in Rust.

Shellcode Reflective DLL Injection (sRDI) Shellcode reflective DLL injection (sRDI) is a process injection technique that allows us to convert a given

null 242 Jul 5, 2023
Process Injection via Component Object Model (COM) IRundown::DoCallback().

COM PROCESS INJECTION for RUST Process Injection via Component Object Model (COM) IRundown::DoCallback(). 该技术由 @modexpblog 挖掘发现,在我对该技术进行深入研究过程中,将原项目 m

Lane 7 Jan 20, 2023
Black-box integration tests for your REST API using the Rust and its test framework

restest Black-box integration test for REST APIs in Rust. This crate provides the [assert_api] macro that allows to declaratively test, given a certai

IOmentum 10 Nov 23, 2022
`boxy` - declarative box-drawing characters

boxy - declarative box-drawing characters Box-drawing characters are used extensively in text user interfaces software for drawing lines, boxes, and o

Miguel Young 7 Dec 30, 2022
Benson Box built on Substrate for a world UNcorporated.

Benson Box Benson Box built on Substrate. For getting started and technical guides, please refer to the Benson Wiki. Contributing All PRs are welcome!

Arthur·Thomas 13 Mar 13, 2022
Boxxy puts bad Linux applications in a box with only their files.

boxxy is a tool for boxing up misbehaving Linux applications and forcing them to put their files and directories in the right place, without symlinks!

amy null 910 Feb 22, 2023
zero-dependency 3d math library in rust

dualquat A lightweight, zero-dependency 3d math library for use in Dual Quaternion based physics simulation. Capable of representing and transforming

null 4 Nov 11, 2022
python dependency vulnerability scanner, written in Rust.

?? Pyscan A dependency vulnerability scanner for your python projects, straight from the terminal. ?? blazingly fast scanner that can be used within l

Aswin. 80 Jun 4, 2023
A zero-dependency crate for writing repetitive code easier and faster.

akin A zero-dependency crate for writing repetitive code easier and faster. Check Syntax for information about how to use it. Why? Example Syntax NONE

LyonSyonII 36 Dec 29, 2022