sark-h2 0.28.3

Fiber-free HTTP/2 protocol primitives and manifold server for sark
use core::ops;

use dope::core::BranchError;
use o3::buffer::resident;
use sark_core::decode::{self, exec, request};
use sark_http::{field::metadata::section::rules, payload::owned, request::body::Error};

use crate::{
    conn::{event, machine},
    frame::numbers,
    server::response::{self, Encoder, Handoff},
    stream,
};

pub(in crate::server) fn try_dispatch<'d, R, M, E, F>(
    ready: request::Ready<exec::Sync, R::Prepared, owned::Segments<'d>>,
    router: &R,
    conn: &mut machine::Connection<
        crate::ServerRole,
        F,
        resident::Shared<'d>,
        rules::RejectPush,
        E,
    >,
    stream: stream::Key,
) -> Result<
    ops::ControlFlow<response::Head<'d>, response::Receipt<'d>>,
    (
        BranchError<crate::conn::Error, numbers::ErrorCode>,
        stream::Key,
    ),
>
where
    R: decode::Decode,
    M: Handoff,
    E: event::Evidence,
    F: rules::Policy,
{
    ready.with_input(|prepared, input| {
        let (outcome, owner) = router
            .try_project(prepared, input, |scoped| {
                let (request, slot) = scoped.into_parts();
                let encoder = Encoder::selected(conn, stream, slot);
                let prepared = match router.try_dispatch(request, encoder) {
                    Ok(prepared) => prepared,
                    Err((error, failed)) => {
                        use decode::dispatch::Error;

                        let error = match error {
                            Error::Busy | Error::Sequence(_) => {
                                BranchError::Second(numbers::ErrorCode::RefusedStream)
                            }
                            Error::Encode(error) => BranchError::First(error),
                            Error::Pending
                            | Error::Moved
                            | Error::Unsupported
                            | Error::Invalid(_) => {
                                BranchError::Second(numbers::ErrorCode::InternalError)
                            }
                            Error::Body(never) => match never {},
                        };
                        return Err((error, failed));
                    }
                };
                let failed = prepared.stream();
                let detached = prepared
                    .detach::<M>()
                    .map_err(|error| (BranchError::First(error), failed))?;
                Ok((detached, failed))
            })
            .map_err(|failure| {
                let code = match failure.discard() {
                    Error::Borrowed { .. } | Error::Retention { .. } | Error::Owned(_) => {
                        numbers::ErrorCode::InternalError
                    }
                };
                (BranchError::Second(code), stream)
            })?;
        let (detached, failed) = outcome?;
        detached
            .defer(owner)
            .map_err(|error| (BranchError::First(error), failed))
    })
}