Skip to main content

quickstart/
quickstart.rs

1//! 最小示例:provider 插件 + 依赖它的 consumer。
2//!
3//! 运行:`cargo run -p rutis --example quickstart`
4//!
5//! 预期输出:
6//! ```text
7//! [listener] loaded: hello from greeter v1
8//! [listener] loaded: hello from greeter v2
9//! done: consumer reloaded without touching it
10//! ```
11//!
12//! 第二行是 rutis 的核心能力在起作用:没有人为 consumer 做任何事,
13//! provider 换代(旧卸载 + 新提供)驱动它自动驱逐并重载。
14
15use rutis::{BoxFuture, CordisError, Ctx, Effect, FiberState, FiberView, Plugin, TypeKey};
16
17/// 一个服务:类型即键,`Greeting` 类型的注册槽全局唯一。
18struct Greeting(String);
19
20/// provider 插件:apply 时把服务放进注册表,卸载时自动摘除。
21struct Greeter {
22    version: u32,
23}
24
25impl Plugin for Greeter {
26    fn name(&self) -> &str {
27        "greeter"
28    }
29    fn apply<'a>(&'a self, ctx: &'a Ctx) -> BoxFuture<'a, Result<Effect, CordisError>> {
30        let greeting = Greeting(format!("hello from greeter v{}", self.version));
31        Box::pin(async move {
32            ctx.provide(greeting)?;
33            Ok(Effect::Done)
34        })
35    }
36}
37
38/// consumer 插件:声明依赖 `Greeting`——声明了,装载时机就交给框架。
39struct Listener {
40    deps: Vec<TypeKey>,
41}
42
43impl Plugin for Listener {
44    fn name(&self) -> &str {
45        "listener"
46    }
47    fn injects(&self) -> &[TypeKey] {
48        &self.deps // 依赖未就绪则停在 Pending,就绪后自动装载
49    }
50    fn apply<'a>(&'a self, ctx: &'a Ctx) -> BoxFuture<'a, Result<Effect, CordisError>> {
51        Box::pin(async move {
52            let greeting = ctx.require::<Greeting>()?.0.clone();
53            println!("[listener] loaded: {greeting}");
54            Ok(Effect::Done)
55        })
56    }
57}
58
59/// 等待 fiber 进入 Active。注意 settle(`(&view).await`)只保证
60/// "处理完此前的意图"——Pending 也是稳定态;等"已装载"要看状态。
61async fn wait_active(view: &FiberView) {
62    let mut rx = view.watch();
63    loop {
64        if matches!(rx.borrow().state, FiberState::Active) {
65            return;
66        }
67        rx.changed().await.expect("fiber driver alive");
68    }
69}
70
71#[tokio::main]
72async fn main() -> Result<(), Box<dyn std::error::Error>> {
73    let ctx = Ctx::root()?;
74
75    // 1. 先装 consumer:依赖未到,它停在 Pending(依赖门控)。
76    let listener = ctx.plugin(Listener {
77        deps: vec![TypeKey::of::<Greeting>()],
78    });
79
80    // 2. provider 到位 → 门控放行,consumer 自动装载。
81    let v1 = ctx.plugin(Greeter { version: 1 });
82    wait_active(&listener).await; // apply 已打印第一行
83
84    // 3. 换 provider:旧的卸载、服务摘除,consumer 被驱逐回 Pending;
85    //    新 provider 提供同类型服务,consumer 自动重载——打印第二行。
86    //    全程没有碰过 consumer。
87    v1.dispose().await?;
88    let _v2 = ctx.plugin(Greeter { version: 2 });
89    wait_active(&listener).await;
90    println!("done: consumer reloaded without touching it");
91    Ok(())
92}