15 个版本 (1 个稳定版)
1.0.0 | 2024年7月5日 |
---|---|
1.0.0-alpha.8 | 2023年8月14日 |
1.0.0-alpha.3 | 2023年7月2日 |
0.3.0 | 2020年6月2日 |
0.1.2 | 2018年10月29日 |
#266 在 Rust 模式
每月下载量:2,554
55KB
1K SLoC
气溶胶
简单的 Rust 依赖注入
lib.rs
:
气溶胶
简单而强大的 Rust 依赖注入。
这个包提供了 Aero
类型,用于根据类型存储依赖项(称为资源)。资源可以在应用程序启动时急切地构建,或者在首次需要时按需构建。资源可以在创建时访问和/或初始化其他资源。
该包将检测依赖循环(如果构建资源 A 需要 B,而 B 本身又需要 A),在这种情况下会引发 panic 而不是栈溢出。
Aero
类型有一个可选的类型参数,用于使某些资源 必需。当资源必需时,可以可靠地访问它。存在一个名为 Aero![...]
的宏,可以轻松地为具有特定必需资源集的 Aero
命名。
克隆或类型转换 Aero
类型成本低(相当于克隆 Arc
)。
可选功能
async
允许异步构建资源,并提供相应的 AsyncConstructibleResource
特性。
axum
提供与 axum
网络框架的集成。有关更多信息,请参阅 axum
模块。
示例用法
use std::{sync::Arc, any::Any};
use aerosol::{Aero, Constructible};
// Here, we can list all the things we want to guarantee are in
// our app state. This is entirely optional, we could also just
// use the `Aero` type with default arguments and check that
// resources are present at runtime.
type AppState = Aero![
Arc<PostmarkClient>,
Arc<dyn EmailSender>,
ConnectionPool,
MessageQueue,
MagicNumber,
];
fn main() {
let app_state: AppState = Aero::new()
// Directly add a resource which doesn't implement `Constructible`.
.with(MagicNumber(42))
// Construct an `Arc<PostmarkClient>` resource in the AppState
.with_constructed::<Arc<PostmarkClient>>()
// Check that an implementation of `EmailSender` was added as a result
.assert::<Arc<dyn EmailSender>>()
// Automatically construct anything else necessary for our AppState
// (in this case, `ConnectionPool` and `MessageQueue`)
.construct_remaining();
// Add an extra resource
app_state.insert("Hello, world");
run(app_state);
}
fn run(app_state: AppState) {
// The `get()` method is infallible because the `Arc<dyn EmailSender>` was
// explicitly listed when defining our `AppState`.
let email_sender: Arc<dyn EmailSender> = app_state.get();
email_sender.send(/* email */);
// We have to use `try_get()` here because a `&str` is not guaranteed to
// exist on our `AppState`.
let hello_message: &str = app_state.try_get().unwrap();
println!("{hello_message}");
// ... more application logic
}
// The `Constructible` trait can be implemented to allow resources to be automatically
// constructed.
impl Constructible for PostmarkClient {
type Error = anyhow::Error;
fn construct(aero: &Aero) -> Result<Self, Self::Error> {
PostmarkClient::new(/* initialize using environment variables */)
}
fn after_construction(this: &(dyn Any + Send + Sync), aero: &Aero) -> Result<(), Self::Error> {
// We can use this to automatically populate extra resources on the context.
// For example, in this case we can make it so that if an `Arc<PostmarkClient>` gets
// constructed, we also provide `Arc<dyn EmailSender>`.
if let Some(arc) = this.downcast_ref::<Arc<Self>>() {
aero.insert(arc.clone() as Arc<dyn EmailSender>)
}
Ok(())
}
}
impl Constructible for ConnectionPool {
type Error = anyhow::Error;
fn construct(aero: &Aero) -> Result<Self, Self::Error> {
// ...
}
}
impl Constructible for MessageQueue {
type Error = anyhow::Error;
fn construct(aero: &Aero) -> Result<Self, Self::Error> {
// ...
}
}
实现细节
Aero
类型管理从资源类型到“插槽”的映射的共享所有权。对于给定的资源类型,相应的“插槽”可以处于以下三种状态之一
- 不存在。在映射中不存在此资源的实例。
- 存在。在映射中存在此资源的实例,可以立即访问。
- 构建中。此资源的实例目前正在构建中,构建完成后可以访问。插槽维护一个等待此资源构建的线程或任务列表,并在资源可用时唤醒它们。
资源可以同步构建,也可以(当功能启用时)异步构建。
如果资源在构建过程中被访问,调用者将等待构建完成。调用者根据是否使用 obtain()
或 obtain_async()
来确定等待是同步还是异步。
在任务中对正在异步构建的资源同步等待,或者在线程中对正在同步构建的资源异步等待,是可能(并且允许)的。
依赖关系
~1.9–9.5MB
~87K SLoC