rutis 0.2.2

Cordis core paradigms in idiomatic Rust: plugin assembly, fiber lifecycle, typed service registry, dependency-driven reload
Documentation
//! 终态释放(0.2.1)单元验证:依赖声明随驱动退出注销,keyed 声明
//! (每实例唯一限定名)在长寿 root 下不累积 `inject_index`。

use super::*;
use crate::ctx::Ctx;
use crate::{BoxFuture, CordisError, Effect, Plugin};
use std::time::Duration;

struct Declares {
    keys: Vec<TypeKey>,
}

impl Plugin for Declares {
    fn name(&self) -> &str {
        "declares"
    }

    fn injects(&self) -> &[TypeKey] {
        &self.keys
    }

    fn apply<'a>(&'a self, _ctx: &'a Ctx) -> BoxFuture<'a, Result<Effect, CordisError>> {
        Box::pin(async { Ok(Effect::Done) })
    }
}

#[tokio::test]
async fn churn_injects_release_index() {
    let ctx = Ctx::root().expect("runtime in scope");
    for i in 0..25 {
        let key = TypeKey::keyed_dynamic::<u32>(format!("dep/{i}"));
        // 依赖永不满足:保持 Pending,直接 dispose 进终态
        let view = ctx.plugin(Declares { keys: vec![key] });
        view.dispose().await.unwrap();
        drop(view);
    }
    for _ in 0..500 {
        let empty = ctx
            .shared()
            .registry
            .inject_index
            .lock()
            .unwrap()
            .is_empty();
        if empty {
            break;
        }
        tokio::time::sleep(Duration::from_millis(2)).await;
    }
    let index = ctx.shared().registry.inject_index.lock().unwrap();
    assert!(
        index.is_empty(),
        "inject declarations must unregister on terminal exit"
    );
}