sark-h2 0.26.0

Fiber-free HTTP/2 protocol primitives and manifold server for sark
use o3::buffer::pool;
use sark_http::field::metadata::{
    block, lower,
    section::{rules, state, storage},
};
use state::decode::{Final, Session};

use crate::{
    conn,
    conn::ingress::{Decode, header},
    hpack::{
        decode,
        decode::{limit, phase::Phase},
    },
};

mod hpack;
pub(in crate::conn::ingress) mod output;

pub(in crate::conn::ingress) struct Header<P: rules::Policy> {
    session: Session<P>,
}

impl<P: rules::Policy> Header<P> {
    pub(in crate::conn::ingress) fn try_new(
        lease: pool::Span,
        kind: rules::Kind,
        connect: block::Connect,
        scratch: storage::Scratch,
    ) -> Result<Self, (storage::Scratch, lower::Error)> {
        Session::try_new(lease, kind, connect, scratch).map(|session| Self { session })
    }

    pub(in crate::conn::ingress) fn hpack<A: rules::Push>(self) -> hpack::Hpack<P, A> {
        hpack::Hpack::new(self.session)
    }

    pub(in crate::conn::ingress) fn finish_block(
        self,
        block: Phase<Decode>,
        budget: limit::Budget,
    ) -> Result<(decode::Decoder, storage::Scratch, output::Decoded<P>), conn::Error> {
        let decoder = match block.finish() {
            Ok(done) => done,
            Err(cause) => {
                drop(self.recycle());
                return Err(conn::Error::Hpack(cause));
            }
        };
        let (scratch, decoded) = self.finish(budget.admission)?;
        Ok((decoder, scratch, decoded))
    }

    pub(in crate::conn::ingress) fn finish(
        self,
        admit: limit::Admission,
    ) -> Result<(storage::Scratch, output::Decoded<P>), conn::Error> {
        let (scratch, result) = self.session.finish();
        let head = result.map_err(conn::Error::Header)?;
        let check = match &head {
            Final::Rejected(rejected) => {
                let (sealed, finished) = rejected.validation();
                header::Validation::new(admit, sealed, finished)
            }
            Final::Request(_) | Final::Response(_) | Final::Other(_) => {
                header::Validation::new(admit, block::Validation::Valid, block::Validation::Valid)
            }
        };
        Ok((
            scratch,
            output::Decoded {
                head,
                validation: check,
            },
        ))
    }

    pub(in crate::conn::ingress) fn recycle(self) -> storage::Scratch {
        self.session.recycle()
    }
}