sark-h2 0.23.0

Fiber-free HTTP/2 protocol primitives and manifold server for sark
Documentation
use std::convert::Infallible;

use o3::{alloc, buffer::resident};
use sark_core::{
    decode::{self, request},
    manifold::{
        schedule,
        server::{app, drain, timing},
    },
};
use sark_http::field::metadata::section::rules;

use crate::{
    conn::{config, event, machine},
    server::{
        self,
        sync::{Book, Dispatch},
    },
};

#[doc(hidden)]
pub struct Route<R> {
    router: R,
    limits: server::Config,
}

impl<R> Route<R> {
    pub(in crate::server) const fn new(router: R, limits: server::Config) -> Self {
        Self { router, limits }
    }

    pub(super) const fn router(&self) -> &R {
        &self.router
    }

    pub(super) const fn limits(&self) -> server::Config {
        self.limits
    }
}

impl<R> app::Spec for Route<R>
where
    R: decode::Decode,
    R::Prepared: request::Synchronous,
{
    type Failure = Infallible;
    type Fields = R::Plan;
    type Egress<'d> = R::Egress<'d>;

    fn layout(&self) -> app::Layout {
        app::Layout::new(
            config::DEFAULT_STREAM_CAPACITY,
            self.limits.max_connection_body_bytes,
        )
    }
}

impl<'d, R, O>
    app::Application<
        'd,
        machine::Connection<
            crate::ServerRole,
            R::Plan,
            resident::Shared<'d>,
            rules::RejectPush,
            event::Ignore,
        >,
        O,
    > for Route<R>
where
    R: Dispatch<'d>,
    O: Copy,
{
    type State = Book<'d, R>;
    type Timing = timing::Off;
    type Build = alloc::Error;

    fn state(&self, capacity: app::Capacity) -> Result<Self::State, alloc::Error> {
        let streams = capacity.streams();
        Book::try_new(streams)
    }

    fn drive(
        &mut self,
        state: &mut Self::State,
        carrier: &mut machine::Connection<
            crate::ServerRole,
            R::Plan,
            resident::Shared<'d>,
            rules::RejectPush,
            event::Ignore,
        >,
        turn: &mut app::Turn<'_, '_, '_, '_, 'd, O>,
        egress: schedule::Egress,
        _: impl FnMut(app::Error<crate::conn::Error, Self::Failure>),
    ) -> Result<drain::Progress, app::Error<crate::conn::Error, Self::Failure>> {
        if matches!(egress, schedule::Egress::Released) {
            match Self::State::has_input(carrier) {
                true => {
                    self.router
                        .pump::<true, _>(state, carrier, self.limits, egress, || {
                            turn.work().permit()
                        });
                }
                false => {
                    self.router
                        .pump::<false, _>(state, carrier, self.limits, egress, || {
                            turn.work().permit()
                        });
                }
            }
        }
        let progress = self.router.drive(state, carrier, self.limits, turn.work());
        if !Self::State::has_events(carrier) {
            self.router.pump::<false, _>(
                state,
                carrier,
                self.limits,
                schedule::Egress::Unchanged,
                || turn.work().permit(),
            );
        }
        if Self::State::has_events(carrier) || state.has_ready() {
            turn.wake().wake();
        }
        Ok(progress)
    }

    fn close(
        &mut self,
        state: &mut Self::State,
        carrier: &mut machine::Connection<
            crate::ServerRole,
            R::Plan,
            resident::Shared<'d>,
            rules::RejectPush,
            event::Ignore,
        >,
        _: O,
    ) {
        self.router.clear(state, carrier);
    }

    fn activity(state: &Self::State) -> schedule::Quiescence {
        if state.runtime.is_empty() {
            schedule::Quiescence::Quiet
        } else {
            schedule::Quiescence::Busy
        }
    }
}