use core::fmt;
use crate::qpack::integer::{QpackInteger, QpackIntegerParseError};
mod builder;
pub use builder::{
QpackDecoderInstructionBuildError, QpackInsertCountIncrementBuilder,
QpackSectionAcknowledgmentBuilder, QpackStreamCancellationBuilder,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum QpackDecoderInstruction<'a> {
SectionAcknowledgment(QpackSectionAcknowledgment<'a>),
StreamCancellation(QpackStreamCancellation<'a>),
InsertCountIncrement(QpackInsertCountIncrement<'a>),
}
impl<'a> QpackDecoderInstruction<'a> {
pub fn parse(bytes: &'a [u8]) -> Result<Self, QpackDecoderInstructionParseError> {
let first = *bytes
.first()
.ok_or(QpackDecoderInstructionParseError::DispatchIncomplete)?;
if first & 0x80 != 0 {
let stream_id = QpackInteger::parse(bytes, 7)
.map_err(QpackDecoderInstructionParseError::SectionAcknowledgment)?;
return Ok(Self::SectionAcknowledgment(QpackSectionAcknowledgment {
bytes: stream_id.as_bytes(),
stream_id,
}));
}
if first & 0xc0 == 0x40 {
let stream_id = QpackInteger::parse(bytes, 6)
.map_err(QpackDecoderInstructionParseError::StreamCancellation)?;
return Ok(Self::StreamCancellation(QpackStreamCancellation {
bytes: stream_id.as_bytes(),
stream_id,
}));
}
let increment = QpackInteger::parse(bytes, 6)
.map_err(QpackDecoderInstructionParseError::InsertCountIncrement)?;
Ok(Self::InsertCountIncrement(QpackInsertCountIncrement {
bytes: increment.as_bytes(),
increment,
}))
}
pub const fn as_bytes(self) -> &'a [u8] {
match self {
Self::SectionAcknowledgment(instruction) => instruction.as_bytes(),
Self::StreamCancellation(instruction) => instruction.as_bytes(),
Self::InsertCountIncrement(instruction) => instruction.as_bytes(),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct QpackSectionAcknowledgment<'a> {
bytes: &'a [u8],
stream_id: QpackInteger<'a>,
}
impl<'a> QpackSectionAcknowledgment<'a> {
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
pub const fn stream_id(self) -> QpackInteger<'a> {
self.stream_id
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct QpackStreamCancellation<'a> {
bytes: &'a [u8],
stream_id: QpackInteger<'a>,
}
impl<'a> QpackStreamCancellation<'a> {
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
pub const fn stream_id(self) -> QpackInteger<'a> {
self.stream_id
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct QpackInsertCountIncrement<'a> {
bytes: &'a [u8],
increment: QpackInteger<'a>,
}
impl<'a> QpackInsertCountIncrement<'a> {
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
pub const fn increment(self) -> QpackInteger<'a> {
self.increment
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum QpackDecoderInstructionParseError {
DispatchIncomplete,
SectionAcknowledgment(#[doc = "The nested stream-ID failure."] QpackIntegerParseError),
StreamCancellation(#[doc = "The nested stream-ID failure."] QpackIntegerParseError),
InsertCountIncrement(#[doc = "The nested increment failure."] QpackIntegerParseError),
}
impl fmt::Display for QpackDecoderInstructionParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DispatchIncomplete => {
f.write_str("QPACK decoder instruction input is incomplete")
}
Self::SectionAcknowledgment(error) => {
write!(f, "QPACK Section Acknowledgment is invalid: {error}")
}
Self::StreamCancellation(error) => {
write!(f, "QPACK Stream Cancellation is invalid: {error}")
}
Self::InsertCountIncrement(error) => {
write!(f, "QPACK Insert Count Increment is invalid: {error}")
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct QpackDecoderInstructions<'a> {
bytes: &'a [u8],
}
impl<'a> QpackDecoderInstructions<'a> {
pub fn parse(bytes: &'a [u8]) -> Result<Self, QpackDecoderInstructionsParseError> {
let mut offset = 0usize;
while offset < bytes.len() {
let instruction = QpackDecoderInstruction::parse(&bytes[offset..])
.map_err(|error| QpackDecoderInstructionsParseError { offset, error })?;
offset += instruction.as_bytes().len();
}
Ok(Self { bytes })
}
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
pub const fn iter(self) -> QpackDecoderInstructionIter<'a> {
QpackDecoderInstructionIter {
remaining: self.bytes,
offset: 0,
failed: false,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct QpackDecoderInstructionsParseError {
pub offset: usize,
pub error: QpackDecoderInstructionParseError,
}
impl fmt::Display for QpackDecoderInstructionsParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"QPACK decoder instruction sequence is invalid at byte {}: {}",
self.offset, self.error
)
}
}
#[derive(Clone, Copy, Debug)]
pub struct QpackDecoderInstructionIter<'a> {
remaining: &'a [u8],
offset: usize,
failed: bool,
}
impl<'a> Iterator for QpackDecoderInstructionIter<'a> {
type Item = Result<QpackDecoderInstruction<'a>, QpackDecoderInstructionsParseError>;
fn next(&mut self) -> Option<Self::Item> {
if self.failed || self.remaining.is_empty() {
return None;
}
match QpackDecoderInstruction::parse(self.remaining) {
Ok(instruction) => {
let consumed = instruction.as_bytes().len();
self.remaining = &self.remaining[consumed..];
self.offset += consumed;
Some(Ok(instruction))
}
Err(error) => {
self.failed = true;
Some(Err(QpackDecoderInstructionsParseError {
offset: self.offset,
error,
}))
}
}
}
}
impl core::iter::FusedIterator for QpackDecoderInstructionIter<'_> {}