roplat 0.2.0

roplat: just a robot operation system
Documentation
/// 迭代器适配器:让静态数据集和算法生成器能直接接�?roplat
///
/// Iterator 无法处理反馈。如果你需�?闭环仿真"(即节点的输出影响下一次迭代器的输入)�?
/// 那么 Iterator 模式就不够用了。那种情况需要定义一个专门的 SimulatorRhythm�?
use std::future::Future;
use std::time::Duration;

use tokio::time::{MissedTickBehavior, interval};

use crate::RoplatError;
use crate::rhythm::Rhythm;

// ============================================================================
// 第一部分:为所�?Iterator 实现 Rhythm (全速运�?
// ============================================================================

/// 为所�?Iterator 实现 Rhythm trait
///
/// # 使用场景
/// - 离线仿真:快速验证算�?
/// - 批处理:处理静态数据集
/// - 算法生成器:数学序列生成
/// - 数据回放:无需时间控制的快速回�?
///
/// # 示例
/// ```no_run
/// # use roplat::rhythm::Rhythm;
/// # async fn example() {
/// // 可以直接对数组调�?drive()
/// [1, 2, 3, 4, 5].into_iter().drive((), |nodes, x| async move {
///     println!("{}", x);
///     ((), nodes)
/// }).await;
/// # }
/// ```
impl<I> Rhythm for I
where
    I: Iterator + Send, // 迭代器本身必须能跨线程移�?
    I::Item: Send,      // 产生的数据必须能跨线程发�?
{
    // 定义产出:直接使用迭代器�?Item
    type Yield = I::Item;

    // 定义反馈:标�?Iterator 不接受反馈,所以设�?()
    type Feed = ();

    type Output = ();
    type Error = 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,
    {
        for item in self {
            let ((), returned_nodes) = op_domain(nodes, item).await;
            nodes = returned_nodes;
            tokio::task::yield_now().await;
        }
        ((), nodes)
    }
}

// ============================================================================
// 第二部分:WithPeriod Trait (为迭代器添加周期)
// ============================================================================

/// 为类型添加周期控制的能力
///
/// # 关联类型
/// * `WithPeriod` - 应用周期后的类型
pub trait WithPeriod: Sized {
    /// 应用周期控制的返回类�?
    type WithPeriod;

    /// 为迭代器添加周期控制
    ///
    /// # 参数
    /// * `period` - 每次迭代的时间间�?
    fn with_period(self, period: Duration) -> Self::WithPeriod;
}

/// 为所�?Iterator 实现 WithPeriod
impl<I: Iterator> WithPeriod for I {
    type WithPeriod = IterWithPeriod<I>;

    fn with_period(self, period: Duration) -> Self::WithPeriod {
        IterWithPeriod::new(self, period)
    }
}

// ============================================================================
// 第三部分:带周期的迭代器包装�?(IterWithPeriod)
// ============================================================================

/// 带周期的迭代器包装器
///
/// 每隔固定时间从迭代器取出一个元素。用于真实感回放�?
///
/// # 使用场景
/// - 轨迹回放:按录制时的频率回放机器人运动轨�?
/// - 仿真重现:精确重现时间相关的行为
/// - 数据采集:控制采样频�?
/// - 动画播放:控制帧�?
///
/// # MissedTickBehavior 说明
/// - `Skip`: 如果处理耗时超过了周期,跳过错过�?tick(默认)
/// - `Burst`: 如果处理耗时超过了周期,尽可能快地追上进�?
/// - `Delay`: 如果处理耗时超过了周期,延迟执行以维持平均频�?
pub struct IterWithPeriod<I> {
    iter: I,
    period: Duration,
}

impl<I> IterWithPeriod<I> {
    /// 用迭代器与周期构造节律源。
    pub fn new(iter: I, period: Duration) -> Self {
        Self { iter, period }
    }

    /// 设置错过�?tick 行为
    ///
    /// 注意:这个方法需要在 drive 时应用到 timer �?
    /// 由于结构体设计限制,我们暂时只存�?period
    /// 实际行为�?drive 方法中配�?
    pub fn with_missed_tick_behavior(self, _behavior: MissedTickBehavior) -> Self {
        self
    }
}

impl<I> Rhythm for IterWithPeriod<I>
where
    I: Iterator + Send,
    I::Item: Send,
{
    type Yield = I::Item;
    type Feed = ();
    type Output = ();
    type Error = 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 timer = interval(self.period);
        timer.set_missed_tick_behavior(MissedTickBehavior::Skip);

        for item in &mut self.iter {
            timer.tick().await;
            let ((), returned_nodes) = op_domain(nodes, item).await;
            nodes = returned_nodes;
        }
        ((), nodes)
    }
}