pipecircuit 0.0.4

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

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

    pub(super) trait RoutingLaw<'message> {}

    impl<'message, Board> RoutingLaw<'message> for Board
    where
        Board: StateMachine + InPipe<Participant = Board> + OutPipe<Participant = Board>,
        <Board as InPipe>::In<'message>:
            StepInputOf<Board, Outcome = <Board as OutPipe>::Out<'message>>,
    {
    }
}

/// The routing law joining a switchboard's input and output pipes.
///
/// This is a framework implementation detail. Pipecircuit implements it for
/// every participant whose input steps it to exactly its declared output.
#[doc(hidden)]
#[allow(private_bounds)]
pub trait RoutesInPipeToOutPipe<'message>:
    StateMachine + InPipe + OutPipe + private::RoutingLaw<'message>
{
    #[must_use = "switchboard outputs must be routed or settled"]
    #[doc(hidden)]
    fn route_turn(
        &mut self,
        input: <Self as InPipe>::In<'message>,
    ) -> <Self as OutPipe>::Out<'message>;
}

impl<'message, Board> RoutesInPipeToOutPipe<'message> for Board
where
    Board: StateMachine + InPipe<Participant = Board> + OutPipe<Participant = Board>,
    <Board as InPipe>::In<'message>:
        StepInputOf<Board, Outcome = <Board as OutPipe>::Out<'message>>,
{
    #[inline(always)]
    fn route_turn(
        &mut self,
        input: <Self as InPipe>::In<'message>,
    ) -> <Self as OutPipe>::Out<'message> {
        self.step(input)
    }
}

/// An exhaustive semantic router at the center of one circuit.
///
/// A switchboard is itself a participant with both directional pipes. Its
/// input is the addressed sum of participant outputs. Its output is the
/// addressed sum of participant inputs and terminal facts. For every message
/// lifetime, that input must step the switchboard to exactly that output.
pub trait Switchboard:
    StateMachine
    + InPipe<Participant = Self>
    + OutPipe<Participant = Self>
    + for<'message> RoutesInPipeToOutPipe<'message>
{
    #[must_use = "switchboard outputs must be routed or settled"]
    #[inline(always)]
    fn route<'message>(
        &mut self,
        input: <Self as InPipe>::In<'message>,
    ) -> <Self as OutPipe>::Out<'message> {
        <Self as RoutesInPipeToOutPipe<'message>>::route_turn(self, input)
    }
}

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

    struct Router;

    impl StateMachine for Router {}

    impl InPipe for Router {
        type Participant = Router;
        type In<'message> = &'message str;
    }

    impl OutPipe for Router {
        type Participant = Router;
        type Out<'message> = usize;
    }

    impl Switchboard for Router {}

    impl StepInputOf<Router> for &str {
        type Outcome = usize;

        fn step(self, _router: &mut Router) -> Self::Outcome {
            self.len()
        }
    }

    #[test]
    fn switchboard_routes_its_declared_input_to_its_declared_output() {
        assert_eq!(Router.route("route me"), 8);
    }
}