pipecircuit 0.0.6

Correct. Robust. Fast. Portable.
Documentation
use core::marker::PhantomData;

use crate::Participant;

pub struct Pipe<Destination: Participant, InstalledTransport> {
    transport: InstalledTransport,
    destination: PhantomData<fn() -> Destination>,
}

impl<Destination: Participant, InstalledTransport> Pipe<Destination, InstalledTransport> {
    pub const fn new(transport: InstalledTransport) -> Self {
        Self {
            transport,
            destination: PhantomData,
        }
    }

    pub const fn transport(&self) -> &InstalledTransport {
        &self.transport
    }

    pub const fn transport_mut(&mut self) -> &mut InstalledTransport {
        &mut self.transport
    }

    pub fn into_transport(self) -> InstalledTransport {
        self.transport
    }

    pub(crate) const fn installed_transport_mut(&mut self) -> &mut InstalledTransport {
        &mut self.transport
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{Inline, NoopTurnObserver, StateMachine, StepInputOf, TurnContext};

    struct Recorder(usize);

    impl StateMachine for Recorder {}

    struct Record<'message>(&'message str);

    impl<'message> StepInputOf<Recorder> for Record<'message> {
        type Outcome = &'message str;

        fn step(self, recorder: &mut Recorder) -> Self::Outcome {
            recorder.0 = recorder.0.saturating_add(1);
            self.0
        }
    }

    struct Count;

    impl StepInputOf<Recorder> for Count {
        type Outcome = usize;

        fn step(self, recorder: &mut Recorder) -> Self::Outcome {
            recorder.0
        }
    }

    enum RecorderIn<'message> {
        Record(Record<'message>),
        Count(Count),
    }

    enum RecorderOut<'message> {
        Recorded(&'message str),
        Counted(usize),
    }

    impl crate::Participant for Recorder {
        type In<'message> = RecorderIn<'message>;
        type Out<'message> = RecorderOut<'message>;
    }

    impl<'message> StepInputOf<Recorder> for RecorderIn<'message> {
        type Outcome = RecorderOut<'message>;

        fn step(self, recorder: &mut Recorder) -> Self::Outcome {
            match self {
                Self::Record(input) => RecorderOut::Recorded(input.step(recorder)),
                Self::Count(input) => RecorderOut::Counted(input.step(recorder)),
            }
        }
    }

    #[test]
    fn a_pipe_preserves_each_precise_destination_and_transport_outcome() {
        let mut pipe = Pipe::<Recorder, _>::new(Inline::new(Recorder(0)));
        let mut turn = TurnContext::new(NoopTurnObserver);

        assert!(matches!(
            turn.send_through(&mut pipe, RecorderIn::Record(Record("borrowed"))),
            RecorderOut::Recorded("borrowed")
        ));
        assert!(matches!(
            turn.send_through(&mut pipe, RecorderIn::Count(Count)),
            RecorderOut::Counted(1)
        ));
        assert_eq!(pipe.transport().destination().0, 1);
        assert_eq!(pipe.transport_mut().destination().0, 1);
        assert_eq!(pipe.into_transport().into_destination().0, 1);
    }
}