roplat 0.2.0

roplat: just a robot operation system
Documentation
use std::future::Future;
use std::time::{Duration, Instant};

use crate::rhythm::Rhythm;

#[derive(Debug, Clone, Copy)]
/// 系统定时节律产生的事件元信息。
pub struct EventMeta {
    /// 物理时间�?(单调递增)
    pub timestamp: Instant,

    /// 逻辑周期 (Target Delta)
    /// 注意:这是控制算法应该使用的 dt,而非物理时间�?
    pub delta: Duration,

    /// 物理抖动 (Jitter)
    /// = 实际唤醒时间 - 理想目标时间 (用于系统健康监控)
    pub jitter: Duration,

    /// 序号 (用于检测丢�?
    pub sequence: u32,

    /// 是否为超时唤醒。
    pub is_timeout: bool,
}

/// 固定周期系统定时器节律。
pub struct SysTimer {
    interval: Duration,
}

impl SysTimer {
    /// 用固定周期创建定时器节律。
    pub fn new(interval: Duration) -> Self {
        Self { interval }
    }

    /// �?launch 参数构�?
    ///
    /// YAML 示例:
    /// ```yaml
    /// interval_ms: 10
    /// ```
    pub fn from_launch_params(params: &serde_yaml::Value) -> Self {
        let ms = params
            .get("interval_ms")
            .and_then(|v| v.as_u64())
            .unwrap_or(100);
        Self::new(Duration::from_millis(ms))
    }
}

impl Rhythm for SysTimer {
    type Yield = EventMeta;
    type Feed = ();
    type Output = ();
    type Error = crate::RoplatError;

    async fn drive<N, F, Fut>(
        &mut self,
        mut nodes: N,
        mut op_domain: F,
    ) -> (Self::Output, N)
    where
        N: Send,
        F: FnMut(N, Self::Yield) -> Fut + Send,
        Fut: Future<Output = (Self::Feed, N)> + Send,
    {
        let mut sequence = 0u32;
        let start_time = Instant::now();

        loop {
            let next_target = start_time + self.interval * sequence;
            tokio::time::sleep_until(next_target.into()).await;
            sequence += 1;

            let now = Instant::now();
            let jitter = now
                .checked_duration_since(next_target)
                .unwrap_or(Duration::ZERO);
            let event = EventMeta {
                timestamp: now,
                delta: self.interval,
                jitter,
                sequence,
                is_timeout: jitter > self.interval,
            };

            let ((), returned_nodes) = op_domain(nodes, event).await;
            nodes = returned_nodes;
        }
    }
}