pipecircuit 0.0.1

Correct. Robust. Fast. Portable.
Documentation
use crate::{InPipe, OutPipe, StateMachine, StepInputOf};

mod private {
    use super::{InPipe, OutPipe, StateMachine, StepInputOf};

    pub(super) trait TurnLaw<'message, Input: InPipe, Output: OutPipe> {}

    impl<'message, Machine, Input, Output> TurnLaw<'message, Input, Output> for Machine
    where
        Machine: StateMachine,
        Input: InPipe,
        Output: OutPipe,
        Input::In<'message>: StepInputOf<Machine, Outcome = Output::Out<'message>>,
    {
    }
}

/// The enforced relationship between a circuit's two boundary pipes.
#[doc(hidden)]
#[allow(private_bounds)]
pub trait TurnsCircuitInPipeToOutPipe<'message, Input: InPipe, Output: OutPipe>:
    StateMachine + private::TurnLaw<'message, Input, Output>
{
    #[must_use = "circuit turn outcomes must be delivered or settled"]
    #[doc(hidden)]
    fn turn_boundary(&mut self, input: Input::In<'message>) -> Output::Out<'message>;
}

impl<'message, Machine, Input, Output> TurnsCircuitInPipeToOutPipe<'message, Input, Output>
    for Machine
where
    Machine: StateMachine,
    Input: InPipe,
    Output: OutPipe,
    Input::In<'message>: StepInputOf<Machine, Outcome = Output::Out<'message>>,
{
    #[inline(always)]
    fn turn_boundary(&mut self, input: Input::In<'message>) -> Output::Out<'message> {
        self.step(input)
    }
}

/// An application manifold driven from one outside boundary to the next.
///
/// One turn accepts a value from the circuit's declared input pipe, settles
/// the resulting internal routing cascade, and yields exactly the declared
/// output-pipe value.
pub trait Circuit:
    StateMachine + for<'message> TurnsCircuitInPipeToOutPipe<'message, Self::InPipe, Self::OutPipe>
{
    type InPipe: InPipe;
    type OutPipe: OutPipe;

    #[must_use = "circuit turn outcomes must be delivered or settled"]
    #[inline(always)]
    fn turn<'message>(
        &mut self,
        input: <Self::InPipe as InPipe>::In<'message>,
    ) -> <Self::OutPipe as OutPipe>::Out<'message> {
        <Self as TurnsCircuitInPipeToOutPipe<'message, Self::InPipe, Self::OutPipe>>::turn_boundary(
            self, input,
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    struct TestCircuit;
    struct TestInPipe;
    struct TestOutPipe;

    impl StateMachine for TestCircuit {}
    impl InPipe for TestInPipe {
        type In<'message> = u8;
    }
    impl OutPipe for TestOutPipe {
        type Out<'message> = u16;
    }
    impl StepInputOf<TestCircuit> for u8 {
        type Outcome = u16;

        fn step(self, _circuit: &mut TestCircuit) -> Self::Outcome {
            u16::from(self)
        }
    }
    impl Circuit for TestCircuit {
        type InPipe = TestInPipe;
        type OutPipe = TestOutPipe;
    }

    #[test]
    fn circuit_turn_steps_between_its_declared_boundary_pipes() {
        assert_eq!(TestCircuit.turn(7), 7);
    }
}