16 个版本 (7 个破坏性更新)

0.8.3 2024 年 3 月 26 日
0.8.1 2024 年 2 月 26 日
0.7.0 2023 年 12 月 6 日
0.6.0 2023 年 9 月 11 日

#1008 in 过程宏

Download history 10/week @ 2024-04-14 16/week @ 2024-04-21 2/week @ 2024-04-28 8/week @ 2024-05-05 21/week @ 2024-05-12 72/week @ 2024-05-19 18/week @ 2024-05-26 22/week @ 2024-06-02 47/week @ 2024-06-09 16/week @ 2024-06-16 13/week @ 2024-06-23 4/week @ 2024-06-30 53/week @ 2024-07-07 42/week @ 2024-07-14 18/week @ 2024-07-21 124/week @ 2024-07-28

每月下载 237
3 个 crate 中使用 (通过 rudi)

MIT/Apache

61KB
1.5K SLoC

Rudi

Crates.io version docs.rs docs

英文 | 简体中文

Rudi - 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 {
    #[di]
    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>(), cx.resolve::<C>()) }` 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]`, `#[Transient]` or `#[SingleOwner]` 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()
}

特性

  • 三个作用域:SingletonTransientSingleOwner (示例)。
  • 异步函数和异步构造函数。
  • 可以在 structenumimpl blockfunction 上使用属性宏。
  • 手动和自动注册(感谢 inventory)。
  • 轻松绑定特性和特对象。
  • 使用类型和名称区分不同的实例。
  • 泛型(但必须是单态化和手动注册)(示例)。
  • 条件注册(示例)。
  • 引用(仅限 SingletonSingleOwner 作用域)(示例)。

更复杂的示例

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 {
    #[di]
    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
}

更多示例可以在 示例测试 目录中找到。

致谢

  • Koin:本项目的设计和测试用例受到了Koin的启发。
  • inventory:本项目使用inventory实现自动注册,使得Rust的自动注册变得非常简单。

贡献

感谢您帮助改进项目!我们非常高兴能邀请您加入!

许可证

根据以下任一许可证授权:

贡献

除非您明确声明,否则根据Apache-2.0许可证定义的,您有意提交以包含在作品中的任何贡献,都将根据上述双许可授权,不附加任何额外条款或条件。

依赖项

~0.4–0.9MB
~20K SLoC