21个不稳定版本 (4个重大更改)

0.6.3 2024年7月27日
0.6.0 2024年5月4日
0.5.2 2024年3月29日
0.2.2 2023年10月26日
0.2.0 2023年7月26日

#7 in #事件系统

Download history 235/week @ 2024-04-22 559/week @ 2024-04-29 238/week @ 2024-05-06 174/week @ 2024-05-13 662/week @ 2024-05-20 651/week @ 2024-05-27 937/week @ 2024-06-03 987/week @ 2024-06-10 577/week @ 2024-06-17 730/week @ 2024-06-24 816/week @ 2024-07-01 601/week @ 2024-07-08 570/week @ 2024-07-15 724/week @ 2024-07-22 353/week @ 2024-07-29 124/week @ 2024-08-05

1,875 每月下载量

MIT 许可证

14KB
179

starbase_events

Crates.io Crates.io

starbase 应用程序框架提供的异步事件发射器。这个crate与其他事件系统的工作方式相当不同,因为订阅者可以修改事件数据。正因为如此,我们不能使用消息通道,必须采取额外预防措施来满足 Send + Sync 的要求。

创建事件

事件必须派生自 Event 或实现 Event 特性。

use starbase_events::Event;
use app::Project;

#[derive(Debug, Event)]
pub struct ProjectCreatedEvent(pub Project);

事件数据

事件可以包含可选的数据,该数据传递给订阅者,并可以由订阅者修改。默认情况下,值是单元类型 (()),但可以通过 #[event] 为派生事件自定义,或在手动实现时使用 type Data

use starbase_events::Event;
use std::path::PathBuf;

#[derive(Event)]
#[event(dataset = PathBuf)]
pub struct CacheCheckEvent(pub PathBuf);

// OR

pub struct CacheCheckEvent(pub PathBuf);

impl Event for CacheCheckEvent {
  type Data = PathBuf;
}

创建发射器

发射器负责管理订阅者,并将事件分发给每个订阅者,同时考虑执行流程和一次性订阅者。

每个事件都需要自己的发射器实例。

use starbase_events::Emitter;

let project_created = Emitter::<ProjectCreatedEvent>::new();
let cache_check: Emitter<CacheCheckEvent> = Emitter::new();

使用订阅者

订阅者是异步函数,被注册到发射器中,并在发射器发射事件时执行。它们接收事件对象作为 Arc<T>,以及事件的数据作为 Arc<RwLock<T::Data>>,允许事件不可变地引用,并可以可变或不可变地访问其数据。

use starbase_events::{Event, EventResult, EventState};

async fn update_root(
  event: Arc<ProjectCreatedEvent>,
  data: Arc<RwLock<<ProjectCreatedEvent as Event>::Data>>
) -> EventResult {
  let mut data = data.write().await;
  data.root = new_path;

  Ok(EventState::Continue)
}

emitter.on(subscriber).await; // Runs multiple times
emitter.once(subscriber).await; // Only runs once

此外,我们提供了一个简化函数实现的 #[subscriber] 函数属性。例如,上面的订阅者可以被重写为

#[subscriber]
async fn update_root(mut data: ProjectCreatedEvent) {
  data.root = new_path;
}

当使用 #[subscriber] 时,以下好处适用

  • 返回类型是可选的。
  • 如果 EventState::Continue,则返回值是可选的。
  • 使用 mut event&mut Event 将获取数据的写入锁,否则获取读锁。
  • 省略事件参数将不会获取任何锁。
  • 参数的名称用于 数据,而事件仅仅是 event

控制事件流

订阅者可以通过返回 EventState 来控制事件执行流程,它支持以下变体

  • Continue - 继续到下一个订阅者(默认)。
  • Stop - 在此订阅者之后停止,丢弃后续订阅者。
#[subscriber]
async fn continue_flow(mut event: CacheCheckEvent) {
  Ok(EventState::Continue)
}

#[subscriber]
async fn stop_flow(mut event: CacheCheckEvent) {
  Ok(EventState::Stop)
}

发射和处理结果

当事件被发射时,订阅者在同一线程中按顺序执行,以便每个订阅者可以在必要时修改事件。因此,事件不支持内部值的引用/生命周期,而必须拥有所有内容。

事件可以通过 emit() 方法发射,该方法需要一个拥有的事件(以及拥有的内部数据)。

let data = emitter.emit(ProjectCreatedEvent(owned_project)).await?;

发射在所有修改完成后返回事件数据。

依赖关系

~3.5–5MB
~80K SLoC