3 个不稳定版本
0.2.0 | 2023 年 9 月 15 日 |
---|---|
0.1.1 | 2021 年 4 月 21 日 |
0.1.0 | 2020 年 9 月 1 日 |
在 Rust 模式 中排名 672
每月下载 38 次
27KB
333 行
底盘
受 Dagger 2 启发的 Rust 编译时依赖注入器
目标
- 无需对类进行注解(支持第三方类)
- 无需使用
std::sync::Arc
- 零开销:与手写代码一样快
- 不使用运行时类型信息(由
std::any::Any
引用提供) - 目前依赖于编译器优化,直到min_specialization
稳定。
- 不使用运行时类型信息(由
- (在编译时检测错误,如缺少依赖项或循环依赖项)
- 等待编译时反射或至少
min_specialization
、const_type_id
和const_cmp_type_id
的稳定
- 等待编译时反射或至少
使用
将 chassis
添加到您的 crate 依赖项中
[dependencies]
chassis = "^0.2.0"
结构体将是模块,可以提供具有函数的依赖项,并且自身也可以有依赖项。注意:目前仅支持关联函数!
#[derive(Default)]
pub struct Module;
#[chassis::module]
impl Module {
pub fn provide_something(dep1: Dependency1, dep2: Dependency2) -> Dependency3 {
Dependency3::new(dep1, dep2)
}
// ...
}
特质将是组件。对于每个特质,将创建一个实现的组件。生成的实现将具有 Impl
后缀,例如 ComponentImpl
。还创建了一个 Component::new
函数。
#[chassis::injector(modules = [Module])]
pub trait Component {
fn resolve_main_class(&self) -> MainClass;
}
示例
use std::rc::Rc;
// define your business logic
/// printer trait
pub trait Printer {
fn print(&self, input: &str);
}
/// a printer implementation
pub struct StdoutPrinter;
impl Printer for StdoutPrinter {
fn print(&self, input: &str) {
println!("{}", input);
}
}
/// greeter for messages
pub struct Greeter {
message: String,
printer: Rc<dyn Printer>,
}
impl Greeter {
/// constructor with dependencies
pub fn new(message: String, printer: Rc<dyn Printer>) -> Self {
Self { message, printer }
}
/// your business logic
pub fn say_hello(&self) {
self.printer.print(&self.message);
}
}
/// module that is parsed to create the dependency injection code
#[derive(Default)]
pub struct DemoModule;
// use strong types when in need to distinguish
pub struct Message(String);
/// Define how to create your dependencies
#[chassis::module]
impl DemoModule {
pub fn provide_printer() -> Rc<dyn Printer> {
Rc::new(StdoutPrinter)
}
pub fn provide_message() -> Message {
Message("Hello World".to_string())
}
pub fn provide_greeter(
message: Message,
printer: Rc<dyn Printer>
) -> Greeter {
Greeter::new(message.0, printer)
}
}
/// Define which dependencies you need.
///
/// A struct `DemoComponentImpl` will be created for
/// you which implements `DemoComponent`.
#[chassis::injector(modules = [DemoModule])]
pub trait DemoComponent {
/// request the to create injection code for our main class `Greeter`
fn resolve_greeter(&self) -> Greeter;
}
fn main() {
// use generated component implementation
let injector = <dyn DemoComponent>::new()
.expect("DI container should be consistent");
// Resolve main dependency
// Note: it can not fail at runtime!
let greeter = injector.resolve_greeter();
// enjoy!
greeter.say_hello();
}
单例
通常,对于每个所需的依赖项,都会在模块中调用提供函数。这会导致类型被多次创建。这可能是无意为之。解决方案是使用 singleton
属性。然后将在组件构建时(对 ComponentImpl::new
的调用)仅调用一次提供方法。要求类型实现 Clone
特质。建议对于单例使用共享引用类型,如 Rc
或 Arc
,以便真正只创建一个实例。
示例
#[chassis::module]
impl Module {
#[chassis(singleton)]
pub fn provide_printer() -> Rc<dyn Printer> {
Rc::new(StdoutPrinter)
}
}
限制
- 类型中的生命周期不支持(除
'static
外) - 泛型处理不正确
- 在模块中请求对已注册的非引用类型引用(当
MyType
由模块提供时,请请求&MyType
) - 懒请求(请求提供者而不是具体类型)
- 可选请求(仅当存在时获取)
- 多个提供者(对插件很有用)
- 可能失败的模块函数(在模块中返回
Result
)
许可证
以下任一许可证下授权
- Apache License,版本 2.0(《LICENSE-APACHE》或https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证(《LICENSE-MIT》或http://opensource.org/licenses/MIT)
任选其一。
贡献
除非您明确声明,否则您提交的任何有意包含在作品中的贡献(根据 Apache-2.0 许可证定义),将按照上述方式双授权,不附加任何额外条款或条件。
依赖
~0.6–1MB
~25K SLoC