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 网页编程
每月 159 次下载
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>();
}
限制
- 内部依赖项只能由单个模块导出。
- 模块不支持泛型参数。
使用模块导出公共依赖项
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>();
}
限制
- 公共导出在宏展开时发现。因此,模块必须在任何提供者在其中使用之前展开。
- 此限制仅适用于在同一个 crate 中定义模块和提供者的情况。
- 需要
cargo
构建。运行cargo clean -p nject-macro
以清除损坏的缓存。 - 模块不支持泛型参数。
使用作用域来限制依赖项的作用域
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 应用程序的使用情况。
鸣谢
- Syn - MIT 或 Apache-2.0
- 准引用 - MIT 或 Apache-2.0
- Rust - MIT 或 Apache-2.0
依赖项
~105KB