4 个版本

0.3.0 2020 年 9 月 24 日
0.2.2 2020 年 9 月 21 日
0.2.1 2020 年 9 月 21 日
0.2.0 2020 年 9 月 21 日

#1876 in Rust 模式

Download history 17/week @ 2024-02-19 3/week @ 2024-02-26 74/week @ 2024-04-01

74 每月下载量

Apache-2.0/MIT

23KB
159

依赖注入模式 derive

Rust 宏,可自动为任意结构体实现依赖注入模式。简单的 #[derive(Container)]将为你的结构体的每个字段生成新的获取器和设置器。此外,Container 将实现 Default 特性,其中将使用 Injectable 特性注入每个字段。

简单示例

use derive_di::*;
#[injectable]
#[derive(Default)]
struct InjectableStruct;

#[derive(Container)]
struct MyContainer {
    i_struct: InjectableStruct,
}

为你生成的代码

use derive_di::*;

#[derive(Default)]
struct InjectableStruct;
impl Injectable for InjectableStruct {
    fn get_service() -> Self {
        Default::default()
    }
}

struct MyContainer {
    i_struct: InjectableStruct,
}

impl MyContainer {
    pub fn get_i_struct(&self) -> &InjectableStruct {
        &self.i_struct
    }
    pub fn get_i_struct_mut(&mut self) -> &mut InjectableStruct {
        &mut self.i_struct
    }
    pub fn set_i_struct(&mut self, i_struct: InjectableStruct) {
        self.i_struct = i_struct
    }
}

impl Default for MyContainer {
    fn default() -> Self {
        Self {
            i_struct: Injectable::get_service()
        }
    }
}

附加功能

工厂

你可以将任何工厂传递给 injectable 宏以构建你的结构体。

工厂结构体

你可以在 injectable 宏内部构建你的结构体。

#[injectable(factory => InjectableStruct {inner: "test".to_owned()})]
struct InjectableStruct {
    inner: String,
}

Injectable 将看起来像这样

impl Injectable for InjectableStruct {
    fn get_service() -> Self {
        InjectableStruct {inner: "test".to_owned()}
    }
}

工厂函数

你可以在 injectable 宏内部使用工厂方法构建你的结构体。

fn factory_struct() -> InjectableStruct {
    InjectableStruct {
        inner: "test".to_owned(),
    }
}
#[injectable(factory => factory_struct())]
struct InjectableStruct {
    inner: String,
}

Injectable 将看起来像这样

impl Injectable for InjectableStruct {
    fn get_service() -> Self {
        factory_struct()
    }
}

工厂闭包

你可以在 injectable 宏内部使用工厂闭包构建你的结构体。

#[injectable(factory => || InjectableStruct {inner: "test".to_owned()})]
struct InjectableStruct {
    inner: String,
}

Injectable 将看起来像这样

impl Injectable for InjectableStruct {
    fn get_service() -> Self {
        (|| InjectableStruct {inner: "test".to_owned()})()
    }
}

自动将结构体注入到 dyn Trait 容器字段

使用 inject 宏,你可以轻松解决容器中的 dyn Trait 字段。

#[injectable(factory => InjectableStruct)]
struct InjectableStruct;

trait Getter {
    fn get(&self) -> String;
}

impl Getter for InjectableStruct {
    fn get(&self) -> String {
        "test".to_owned()
    }
}

#[derive(Container)]
struct MyContainer {
    #[inject(InjectableStruct)]
    i_struct: Box<dyn Getter>,
}

MyContainerDefault 实现将看起来像这样

impl Default for MyContainer {
    fn default() -> Self {
        Self {
            i_struct: Box::from(InjectableStruct::get_service())
        }
    }
}

模拟

你可以在容器中组合 dyn Trait 字段和设置器,并为简单测试模拟任何逻辑。

#[injectable(factory => || InjectableStruct)]
struct InjectableStruct;

trait Getter {
    fn get(&self) -> String;
}

impl Getter for InjectableStruct {
    fn get(&self) -> String {
        "test".to_owned()
    }
}

struct GetterMock;
impl Getter for GetterMock {
    fn get(&self) -> String {
        "mocked".to_owned()
    }
}

#[derive(Container)]
struct MyContainer {
    #[inject(InjectableStruct)]
    i_struct: Box<dyn Getter>,
}

fn main() {      
    let mut container = MyContainer::default();
    assert_eq!("test", container.get_i_struct().get());
    container.set_i_struct(Box::from(GetterMock));
    assert_eq!("mocked", container.get_i_struct().get())
}

依赖关系

~1.5MB
~33K SLoC