sark-h2 0.28.1

Fiber-free HTTP/2 protocol primitives and manifold server for sark
use sark_http::{
    field::metadata::{
        block::Value,
        strings::{Cursor, Encoding},
    },
    payload::compress::dynamic::insert::stages,
};

use crate::hpack::decode::{
    self,
    decoder::{Machine, literal, lookup},
    limit, mode,
    phase::Phase,
    strings,
};

pub(in crate::hpack::decode) struct Repr<T> {
    decoder: T,
}

impl<T> Repr<T> {
    pub(in crate::hpack::decode) fn new(decoder: T) -> Self {
        Self { decoder }
    }
}

impl Repr<decode::Decoder> {
    pub(in crate::hpack::decode) fn start<M, S>(
        self,
        budget: &mut limit::Budget,
        first: u8,
        mask: u8,
        target: limit::Integer,
        sink: S,
    ) -> Result<(Phase<M>, S), (S, M::Error)>
    where
        M: mode::Flow<S>,
    {
        let sink = match target {
            limit::Integer::Indexed | limit::Integer::LiteralName(_) => {
                mode::carry(sink, self.decoder.0.core.field(budget))?.1
            }
            limit::Integer::DynamicSize => sink,
        };
        let prefix = first & mask;
        if prefix < mask {
            self.apply(budget, u64::from(prefix), target, sink)
        } else {
            Ok((
                Phase::Integer(self.decoder, limit::Number::new(u64::from(mask)), target),
                sink,
            ))
        }
    }

    pub(in crate::hpack::decode) fn apply<M, S>(
        mut self,
        budget: &mut limit::Budget,
        value: u64,
        target: limit::Integer,
        sink: S,
    ) -> Result<(Phase<M>, S), (S, M::Error)>
    where
        M: mode::Flow<S>,
    {
        match target {
            limit::Integer::Indexed => {
                let (field, sink) =
                    mode::carry(sink, lookup::get(&self.decoder.0.dyn_table, value as usize))?;
                let sink = M::field(sink, budget, field.name(), field.valued())?;
                Ok((Phase::Representation(self.decoder), sink))
            }
            limit::Integer::LiteralName(index) => {
                literal::Literal::new(self.decoder).start(budget, value as usize, index, sink)
            }
            limit::Integer::DynamicSize => {
                let size = value as usize;
                let ((), sink) = mode::carry(sink, self.decoder.resize(budget, size))?;
                Ok((Phase::Representation(self.decoder), sink))
            }
        }
    }

    pub(in crate::hpack::decode) fn name_prefix<M, S>(
        self,
        context: limit::Literal<M>,
        first: u8,
        sink: S,
    ) -> Result<(Phase<M>, S), (S, M::Error)>
    where
        M: mode::Flow<S>,
    {
        let value = first & 0x7f;
        let encoding = match first & 0x80 {
            0 => Encoding::Plain,
            _ => Encoding::Huffman,
        };
        if value < 0x7f {
            self.name_length(context, u64::from(value), encoding, sink)
        } else {
            Ok((
                Phase::ReadyNameLength(
                    self.decoder,
                    context,
                    limit::LengthState {
                        number: limit::Number::new(0x7f),
                        encoding,
                    },
                ),
                sink,
            ))
        }
    }

    pub(in crate::hpack::decode) fn name_length<M, S>(
        mut self,
        context: limit::Literal<M>,
        value: u64,
        encoding: Encoding,
        sink: S,
    ) -> Result<(Phase<M>, S), (S, M::Error)>
    where
        M: mode::Flow<S>,
    {
        if value > strings::MAX_LITERAL_LEN as u64 {
            return Err((sink, decode::Error::BadString.into()));
        }
        let len = value as usize;
        let retain = match (context.route(), encoding) {
            (mode::NameRoute::Retain, Encoding::Huffman) => strings::Retention::Retained,
            (mode::NameRoute::Retain, Encoding::Plain) => match context.limit().admit(len) {
                limit::Admission::Admitted => strings::Retention::Retained,
                limit::Admission::Exceeded => strings::Retention::Counted,
            },
            (mode::NameRoute::Count, _) => strings::Retention::Counted,
        };
        self.decoder.0.core.name_scratch.clear();
        let string = limit::StringState {
            string: Cursor::new(len, encoding),
            validation: Value::new(),
            retention: retain,
        };
        if len != 0 {
            return Ok((Phase::ReadyNameString(self.decoder, context, string), sink));
        }
        let (decoder, context, sink) =
            literal::Literal::new(self.decoder).name(context, 0, retain, sink)?;
        Ok((Phase::ReadyValuePrefix(decoder, context), sink))
    }

    pub(in crate::hpack::decode) fn value_prefix<M, S>(
        self,
        budget: &mut limit::Budget,
        context: limit::Named<M>,
        first: u8,
        sink: S,
    ) -> Result<(Phase<M>, S), (S, M::Error)>
    where
        M: mode::Flow<S>,
    {
        let value = first & 0x7f;
        let encoding = match first & 0x80 {
            0 => Encoding::Plain,
            _ => Encoding::Huffman,
        };
        if value < 0x7f {
            self.value_length(budget, context, u64::from(value), encoding, sink)
        } else {
            Ok((
                Phase::ReadyValueLength(
                    self.decoder,
                    context,
                    limit::LengthState {
                        number: limit::Number::new(0x7f),
                        encoding,
                    },
                ),
                sink,
            ))
        }
    }

    pub(in crate::hpack::decode) fn value_length<M, S>(
        mut self,
        budget: &mut limit::Budget,
        context: limit::Named<M>,
        value: u64,
        encoding: Encoding,
        sink: S,
    ) -> Result<(Phase<M>, S), (S, M::Error)>
    where
        M: mode::Flow<S>,
    {
        if value > strings::MAX_LITERAL_LEN as u64 {
            return Err((sink, decode::Error::BadString.into()));
        }
        let len = value as usize;
        let retain = match (context.route(), encoding) {
            (mode::Route::Retain, Encoding::Huffman) => strings::Retention::Retained,
            (mode::Route::Retain, Encoding::Plain) => match context.limit().admit(len) {
                limit::Admission::Admitted => strings::Retention::Retained,
                limit::Admission::Exceeded => strings::Retention::Counted,
            },
            (mode::Route::Count | mode::Route::Validate | mode::Route::Direct(_), _) => {
                strings::Retention::Counted
            }
        };
        self.decoder.0.core.value_scratch.clear();
        let string = limit::StringState {
            string: Cursor::new(len, encoding),
            validation: Value::new(),
            retention: retain,
        };
        if len != 0 {
            return Ok((Phase::ReadyValueString(self.decoder, context, string), sink));
        }
        let (decoder, sink) =
            literal::Literal::new(self.decoder).value(budget, context, 0, retain, sink)?;
        Ok((Phase::Representation(decoder), sink))
    }
}

impl Repr<Machine<stages::Name>> {
    pub(in crate::hpack::decode) fn prefix<M, S>(
        self,
        context: limit::Literal<M>,
        first: u8,
        sink: S,
    ) -> Result<(Phase<M>, S), (S, M::Error)>
    where
        M: mode::Flow<S>,
    {
        let value = first & 0x7f;
        let encoding = match first & 0x80 {
            0 => Encoding::Plain,
            _ => Encoding::Huffman,
        };
        if value < 0x7f {
            self.length(context, u64::from(value), encoding, sink)
        } else {
            Ok((
                Phase::StagedNameLength(
                    self.decoder,
                    context,
                    limit::LengthState {
                        number: limit::Number::new(0x7f),
                        encoding,
                    },
                ),
                sink,
            ))
        }
    }

    pub(in crate::hpack::decode) fn length<M, S>(
        mut self,
        context: limit::Literal<M>,
        value: u64,
        encoding: Encoding,
        sink: S,
    ) -> Result<(Phase<M>, S), (S, M::Error)>
    where
        M: mode::Flow<S>,
    {
        if value > strings::MAX_LITERAL_LEN as u64 {
            return Err((sink, decode::Error::BadString.into()));
        }
        self.decoder.name_scratch.clear();
        let len = value as usize;
        let string = limit::StringState {
            string: Cursor::new(len, encoding),
            validation: Value::new(),
            retention: strings::Retention::Retained,
        };
        if len != 0 {
            return Ok((Phase::StagedNameString(self.decoder, context, string), sink));
        }
        let (decoder, context, sink) = literal::Literal::new(self.decoder).name(context, sink)?;
        Ok((Phase::StagedValuePrefix(decoder, context), sink))
    }
}

impl Repr<Machine<stages::Value>> {
    pub(in crate::hpack::decode) fn prefix<M, S>(
        self,
        budget: &mut limit::Budget,
        context: limit::Named<M>,
        first: u8,
        sink: S,
    ) -> Result<(Phase<M>, S), (S, M::Error)>
    where
        M: mode::Flow<S>,
    {
        let value = first & 0x7f;
        let encoding = match first & 0x80 {
            0 => Encoding::Plain,
            _ => Encoding::Huffman,
        };
        if value < 0x7f {
            self.length(budget, context, u64::from(value), encoding, sink)
        } else {
            Ok((
                Phase::StagedValueLength(
                    self.decoder,
                    context,
                    limit::LengthState {
                        number: limit::Number::new(0x7f),
                        encoding,
                    },
                ),
                sink,
            ))
        }
    }

    pub(in crate::hpack::decode) fn length<M, S>(
        mut self,
        budget: &mut limit::Budget,
        context: limit::Named<M>,
        value: u64,
        encoding: Encoding,
        sink: S,
    ) -> Result<(Phase<M>, S), (S, M::Error)>
    where
        M: mode::Flow<S>,
    {
        if value > strings::MAX_LITERAL_LEN as u64 {
            return Err((sink, decode::Error::BadString.into()));
        }
        self.decoder.value_scratch.clear();
        let len = value as usize;
        let string = limit::StringState {
            string: Cursor::new(len, encoding),
            validation: Value::new(),
            retention: strings::Retention::Retained,
        };
        if len != 0 {
            return Ok((
                Phase::StagedValueString(self.decoder, context, string),
                sink,
            ));
        }
        let (decoder, sink) = literal::Literal::new(self.decoder).value(budget, context, sink)?;
        Ok((Phase::Representation(decoder), sink))
    }
}

const _: () = assert!(core::mem::size_of::<usize>() >= core::mem::size_of::<u64>());