11 个版本

0.4.3 2024 年 4 月 27 日
0.4.2 2024 年 3 月 24 日
0.4.1 2024 年 2 月 18 日
0.3.1 2023 年 12 月 8 日
0.2.0 2022 年 10 月 21 日

#411 in 网页编程

Download history 178/week @ 2024-04-26 12/week @ 2024-05-03 1/week @ 2024-05-10 19/week @ 2024-05-17 7/week @ 2024-05-24 3/week @ 2024-05-31 16/week @ 2024-06-07 16/week @ 2024-06-14 6/week @ 2024-06-21 144/week @ 2024-07-26 15/week @ 2024-08-02

每月 159 次下载

MIT 许可证

18KB
60

nject


为 Rust 制作的简单零成本依赖注入库

安装

将以下内容添加到您的 Cargo.toml

[dependencies]
nject = "0.4"

为什么选择 nject

  • 零成本:使用此库与手动注入依赖项等效,如基准测试所示。
  • 编译时仅限:如果配置不正确,nject 将在编译时失败。

使用案例

消除在模块间指定依赖项的需求

use nject::{injectable, provider};

#[injectable]
struct DepOne;

#[injectable]
struct DepTwo {
    dep: DepOne,
}

#[injectable]
struct Facade {
    dep: DepTwo,
}

#[provider]
struct Provider;

fn main() {
    let _facade: Facade = Provider.provide();
}

支持生命周期 - 允许共享依赖项

use nject::{injectable, provider};

struct DepOne;

#[injectable]
struct Facade<'a> {
    dep: &'a DepOne,
}

#[provider]
struct Provider {
    #[provide]
    shared: DepOne,
}

fn main() {
    let provider = Provider { shared: DepOne };
    let _facade: Facade = provider.provide();
}

支持 dyn 特性

use nject::{injectable, provider};
use std::rc::Rc;

trait Greeter {
    fn greet(&self);
}

#[injectable]
struct GreeterOne;

impl Greeter for GreeterOne {
    fn greet(&self) {
        println!("Greeting");
    }
}

#[injectable]
struct Facade<'a> {
    boxed_dep: Box<dyn Greeter>,
    ref_dep: &'a dyn Greeter,
    rc_dep: Rc<dyn Greeter>,
}

#[provider]
#[provide(Box<dyn Greeter>, |greeter: GreeterOne| Box::new(greeter))]
struct Provider {
    #[provide(dyn Greeter)]
    greeter: GreeterOne,
    #[provide(Rc<dyn Greeter>, |x| x.clone())]
    rc_greeter: Rc<GreeterOne>,
}

fn main() {
    let provider = Provider { 
        greeter: GreeterOne,
        rc_greeter: Rc::new(GreeterOne),
    };
    let _facade: Facade = provider.provide();
}

支持泛型

use nject::{injectable, provider};

#[injectable]
struct DepOne;

#[injectable]
struct Facade<T> {
    dep: T,
}

#[provider]
struct Provider;

fn main() {
    let _facade: Facade<DepOne> = Provider.provide();
}

支持泛型提供者

use nject::{injectable, provider};

trait Greeter {
    fn greet(&self);
}

#[injectable]
struct DevGreeter;

impl Greeter for DevGreeter {
    fn greet(&self) {
        println!("Greeting Dev");
    }
}

#[injectable]
struct ProdGreeter;

impl Greeter for ProdGreeter {
    fn greet(&self) {
        println!("Greeting production");
    }
}

#[injectable]
struct Facade<'a> {
    dep: &'a dyn Greeter,
}

#[provider]
struct Provider<'a, T: Greeter>(#[provide(dyn Greeter)] &'a T);

fn main() {
    let _dev_facade: Facade = Provider(&DevGreeter).provide();
    let _prod_facade: Facade = Provider(&ProdGreeter).provide();
}

易于注入不可注入的依赖项

use nject::{inject, injectable, provider};

#[inject(Self { non_injectable_value: 123 })]
struct InjectableFromInjectAttr {
    non_injectable_value: i32,
}

struct NonInjectable {
    non_injectable_value: i32,
}

#[inject(|injectable_dep: InjectableFromInjectAttr| Self { 
    non_injectable_value: injectable_dep.non_injectable_value + 10, 
    injectable_dep 
})]
struct PartiallyInjectable {
    non_injectable_value: i32,
    injectable_dep: InjectableFromInjectAttr
}

#[injectable]
struct Facade {
    dep_from_injected: InjectableFromInjectAttr,
    dep_from_partial_inject: PartiallyInjectable,
    #[inject(NonInjectable { non_injectable_value: 456 })]
    dep_from_inject_attr: NonInjectable,
    #[inject(InjectableFromInjectAttr { non_injectable_value: 789 })]
    dep_from_inject_attr_override: InjectableFromInjectAttr,
    #[inject(|injectable_dep: InjectableFromInjectAttr| PartiallyInjectable {
        non_injectable_value: 111, 
        injectable_dep 
    })]
    dep_from_partial_inject_attr_override: PartiallyInjectable,
}

#[provider]
struct Provider;

fn main() {
    let _facade = Provider.provide::<Facade>();
}

使用模块导出内部共享依赖项

use nject::{injectable, provider};

mod sub {
    use nject::{injectable, module};
    use std::rc::Rc;

    trait Greeter {
        fn greet(&self) -> &str;
    }

    #[injectable]
    struct GreeterOne;

    impl Greeter for GreeterOne {
        fn greet(&self) -> &str {
            "One"
        }
    }

    #[injectable]
    struct InternalType(#[inject(123)] i32); // Not visible outside of module.

    struct Ref<T>(Rc<T>);

    #[injectable]
    pub struct Facade<'a> {
        hidden: &'a InternalType,
        hidden_dyn: &'a dyn Greeter,
        hidden_ref: Ref<InternalType>,
    }

    #[injectable]
    #[module]
    pub struct Module {
        // Internal shared type exports must be made on fields (not the struct).
        #[export]
        hidden: InternalType,
        #[export(dyn Greeter)]
        hidden_dyn: GreeterOne,
        #[inject(|x: InternalType| Rc::new(x))]
        #[export(Ref<InternalType>, |x| Ref(x.clone()))]
        hidden_rc: Rc<InternalType>,
    }
}

#[injectable]
#[provider]
struct Provider {
    #[import]
    sub_mod: sub::Module,
}

fn main() {
    #[provider]
    struct InitProvider;

    let provider = InitProvider.provide::<Provider>();
    let _facade = provider.provide::<sub::Facade>();
}

限制

  1. 内部依赖项只能由单个模块导出。
  2. 模块不支持泛型参数。

使用模块导出公共依赖项

use nject::{injectable, provider};

mod sub {
    use nject::{injectable, module};
    use std::boxed::Box;
    use std::rc::Rc;

    pub trait Greeter {
        fn greet(&self) -> &str;
    }

    #[injectable]
    struct GreeterOne;

    impl Greeter for GreeterOne {
        fn greet(&self) -> &str {
            "One"
        }
    }

    #[injectable]
    pub struct Facade<'a> {
        public_box: Box<dyn Greeter>,
        public_rc: Rc<dyn Greeter>,
        public_i32: &'a i32,
    }

    #[injectable]
    // The absolute public path to access the module. 
    // If no path is given, the struct name will be used and must be unique across all modules.
    // Keywords like `crate` and `Self` will be substituted accordingly.
    #[module(crate::sub::Self)]
    // Public type exports must be made on the struct (not the fields). 
    // To prevent name collisions, use absolute paths in types.
    #[export(std::boxed::Box<dyn crate::sub::Greeter>, |x: GreeterOne| Box::new(x))]
    #[export(std::rc::Rc<dyn crate::sub::Greeter>, self.public.clone())]
    #[export(&'prov i32, &123)]
    pub struct Module {
        #[inject(|x: GreeterOne| Rc::new(x))]
        public: Rc<dyn Greeter>,
    }
}

#[injectable]
#[provider]
struct Provider {
    #[import]
    // To import module public exports, use the absolute path given in its definition.
    sub_mod: crate::sub::Module,
}

fn main() {
    #[provider]
    struct InitProvider;

    let provider = InitProvider.provide::<Provider>();
    let _facade = provider.provide::<sub::Facade>();
}

限制

  1. 公共导出在宏展开时发现。因此,模块必须在任何提供者在其中使用之前展开。
    • 此限制仅适用于在同一个 crate 中定义模块和提供者的情况。
  2. 需要 cargo 构建。运行 cargo clean -p nject-macro 以清除损坏的缓存。
  3. 模块不支持泛型参数。

使用作用域来限制依赖项的作用域

use nject::{injectable, module, provider};

#[injectable]
struct ModuleDep;

#[injectable]
#[module]
struct ScopeModule {
    #[export]
    module_dep: ModuleDep,
}

#[injectable]
struct RootDep;

#[injectable]
struct ScopeDep;

#[injectable]
struct ScopeFacade<'a> {
    root_dep: &'a RootDep, 
    scope_dep: &'a ScopeDep,
    scope_module_dep: &'a ModuleDep,
}

#[injectable]
#[provider]
#[scope(ScopeDep)]
#[scope(#[import] ScopeModule)]
#[scope(other: #[arg] &'scope ScopeDep)]
#[scope(other: #[arg] &'scope ModuleDep)]
struct Provider(#[provide] RootDep);

fn main() {
    #[provider]
    struct InitProvider;

    let provider = InitProvider.provide::<Provider>();
    let scope = provider.scope();
    let scope_facade = scope.provide::<ScopeFacade>();

    let other_scope = provider.other_scope(scope_facade.scope_dep, scope_facade.scope_module_dep);
    let _other_scope_facade = other_scope.provide::<ScopeFacade>();
}

注入提供者以进行创建后值注入

use nject::{injectable, provider};

#[injectable]
struct Dep(#[inject(123)] i32);

#[injectable]
struct Factory<'a> {
    dep_provider: &'a dyn nject::Provider<'a, Dep>,
}

impl<'a> Factory<'a> {
    fn create_dep(&self) -> Dep {
        self.dep_provider.provide()
    }
}

#[provider]
struct Provider;

fn main() {
    let factory = Provider.provide::<Factory>();
    let _dep = factory.create_dep();
}

示例

您可以查看 axum/actix 示例,了解 Web API 的使用情况,或查看 Leptos 示例,了解 Web 应用程序的使用情况。

鸣谢

依赖项

~105KB