use super::{
AdmissionHandler, AdmittedPipeDriver, IntakeAdmission, IntakeGate, PipeOutputHandler,
PipeSender, ScopedSender,
};
use crate::Pipe;
#[derive(Debug, Eq, PartialEq)]
pub enum AdmissionFailure<Admission, Conduct> {
Admission(Admission),
Conduct(Conduct),
}
#[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)
}
}