nodo_std 0.18.5

Standard codelets for NODO
Documentation
// Copyright 2023 David Weikersdorfer

use core::marker::PhantomData;
use nodo::prelude::*;

/// A gate can be configured via a (mutable) parameter to either forward all received messages
/// (open), or drop all received messages (closed).
pub struct ParameterGate<T>(PhantomData<T>);

#[derive(Config)]
pub struct ParameterGateConfig {
    #[mutable]
    /// If the gate is open it forwards all received messages.
    /// If the gate is closed it drops all received messages.
    pub is_open: bool,
}

#[derive(Status, Debug, Clone, Copy)]
pub enum ParameterGateStatus {
    #[default]
    #[skipped]
    Unspecified,

    #[skipped]
    /// The gate is open but no messages are passing through
    OpenIdle,

    /// The gate is open and messages are passing through
    OpenBusy(usize),

    #[skipped]
    /// The gate is closed but no messages are passing through
    ClosedIdle,

    /// The gate is closed and messages are blocked from passing through and dropped
    ClosedBusy(usize),
}

impl<T> Default for ParameterGate<T> {
    fn default() -> Self {
        Self(PhantomData)
    }
}

impl<T> Codelet for ParameterGate<T>
where
    T: Send + Sync + Clone,
{
    type Status = ParameterGateStatus;
    type Config = ParameterGateConfig;
    type Rx = DoubleBufferRx<T>;
    type Tx = DoubleBufferTx<T>;
    type Signals = ();

    fn build_bundles(_config: &Self::Config) -> (Self::Rx, Self::Tx) {
        (
            DoubleBufferRx::new_auto_size(),
            DoubleBufferTx::new_auto_size(),
        )
    }

    fn step(
        &mut self,
        cx: Context<Self>,
        rx: &mut Self::Rx,
        tx: &mut Self::Tx,
    ) -> eyre::Result<ParameterGateStatus> {
        let count = rx.len();
        if cx.config.is_open {
            if count == 0 {
                Ok(ParameterGateStatus::OpenIdle)
            } else {
                tx.push_many(rx.drain(..))?;
                Ok(ParameterGateStatus::OpenBusy(count))
            }
        } else {
            if count == 0 {
                Ok(ParameterGateStatus::ClosedIdle)
            } else {
                rx.clear();
                Ok(ParameterGateStatus::ClosedBusy(count))
            }
        }
    }
}