rudi-macro 0.1.0

Macros for Rudi.
Documentation

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(cx.resolve::<A>()) }` as the constructor for `B`
#[Transient]
impl B {
    fn new(a: A) -> B {
        B(a)
    }
}

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

fn main() {
    // Automatically register all types with `#[Singleton]` and `#[Transient]` attributes
    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 constructor.
  • Manual and automatic registration (thanks to inventory).
  • Easy binding of trait objects.
  • Distinguishing different instances with types and names.
  • Support for generics (but not for automatic registration).

More complex example

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

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

// Register async function and specify name
#[Singleton(name = "number")]
async fn number() -> i32 {
    42
}

#[derive(Debug, Clone)]
#[Singleton(async_constructor, name = "foo")] // Register async constructor and specify name
struct Foo {
    #[di("number")] // Specify the name of the dependency
    number: i32,
}

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

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

#[Transient(binds = [Self::into_debug])] // Bind `Bar` to `Rc<dyn Debug>`
impl Bar {
    async fn new(#[di("foo")] f: Foo) -> Bar { // Register async constructor
        Bar(f)
    }
}

#[Singleton]
async fn run(bar: Bar, debug: Rc<dyn Debug>, #[di("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.