pipecircuit 0.0.17

Correct. Robust. Fast. Portable. Pick four.
Documentation
use super::{
    AdmissionHandler, AdmittedPipeDriver, IntakeAdmission, IntakeGate, PipeOutputHandler,
    PipeSender, ScopedSender,
};
use crate::Pipe;

/// An admission refusal is distinct from failure after an output was admitted.
#[derive(Debug, Eq, PartialEq)]
pub enum AdmissionFailure<Admission, Conduct> {
    Admission(Admission),
    Conduct(Conduct),
}

/// Adds a fallible gate while preserving the handler's exact conduction failure.
/// The gate sees only shared policy and peer views; its captured state may mutate.
#[must_use = "use the handler to drive its source with the configured gate"]
pub struct FallibleAdmission<Handler, Gate> {
    handler: Handler,
    gate: Gate,
}

impl<Handler, Gate> FallibleAdmission<Handler, Gate> {
    pub const fn new(handler: Handler, gate: Gate) -> Self {
        Self { handler, gate }
    }
}

impl<Context, Handler, Gate, Admission, Conduct>
    IntakeGate<Context, AdmissionFailure<Admission, Conduct>> for FallibleAdmission<Handler, Gate>
where
    Handler: AdmissionHandler<Context>,
    Gate: FnMut(&Handler::Policy, &Handler::Peers, Context) -> Result<IntakeAdmission, Admission>,
{
    fn admit(
        &mut self,
        context: Context,
    ) -> Result<IntakeAdmission, AdmissionFailure<Admission, Conduct>> {
        let (policy, peers) = self.handler.admission_context();
        (self.gate)(policy, peers, context).map_err(AdmissionFailure::Admission)
    }
}

impl<Protocol, Driver, Handler, Gate, Failure> PipeOutputHandler<Protocol, Driver>
    for FallibleAdmission<Handler, Gate>
where
    Protocol: Pipe,
    Driver: AdmittedPipeDriver<Protocol>,
    Handler: PipeOutputHandler<Protocol, Driver> + AdmissionHandler<Driver::IntakeContext>,
    Gate: FnMut(
        &Handler::Policy,
        &Handler::Peers,
        Driver::IntakeContext,
    ) -> Result<IntakeAdmission, Failure>,
{
    type Failure = AdmissionFailure<Failure, Handler::Failure>;

    fn output<'message, Sender>(
        &mut self,
        output: Protocol::Out<'message>,
        outgoing: &mut Sender,
    ) -> Result<(), Self::Failure>
    where
        Sender: ScopedSender<'message, Protocol>
            + for<'input> PipeSender<Protocol, Outcome<'input> = Driver::Submission<'input>>,
    {
        self.handler
            .output(output, outgoing)
            .map_err(AdmissionFailure::Conduct)
    }
}