use core::fmt;
use crate::qpack::integer::{
QPACK_INTEGER_MAX, QpackInteger, QpackIntegerBuildError, QpackIntegerParseError,
canonical_encoded_len, integer_from_prevalidated, write_canonical_prevalidated,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct QpackFieldSectionPrefix<'a> {
bytes: &'a [u8],
encoded_required_insert_count: QpackInteger<'a>,
negative: bool,
delta_base: QpackInteger<'a>,
}
impl<'a> QpackFieldSectionPrefix<'a> {
pub fn parse(bytes: &'a [u8]) -> Result<Self, QpackFieldSectionPrefixParseError> {
let encoded_required_insert_count = QpackInteger::parse(bytes, 8)
.map_err(QpackFieldSectionPrefixParseError::RequiredInsertCount)?;
let required_insert_count_len = encoded_required_insert_count.as_bytes().len();
let delta_bytes = &bytes[required_insert_count_len..];
let delta_base = QpackInteger::parse(delta_bytes, 7)
.map_err(QpackFieldSectionPrefixParseError::DeltaBase)?;
let length = required_insert_count_len
.checked_add(delta_base.as_bytes().len())
.ok_or(QpackFieldSectionPrefixParseError::LengthOverflow)?;
Ok(Self {
bytes: &bytes[..length],
encoded_required_insert_count,
negative: delta_base.high_bits() & 0x80 != 0,
delta_base,
})
}
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
pub const fn encoded_required_insert_count(self) -> QpackInteger<'a> {
self.encoded_required_insert_count
}
pub const fn is_negative(self) -> bool {
self.negative
}
pub const fn delta_base(self) -> QpackInteger<'a> {
self.delta_base
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum QpackFieldSectionPrefixParseError {
RequiredInsertCount(
#[doc = "The nested Required Insert Count failure."] QpackIntegerParseError,
),
DeltaBase(#[doc = "The nested Delta Base failure."] QpackIntegerParseError),
LengthOverflow,
}
impl fmt::Display for QpackFieldSectionPrefixParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::RequiredInsertCount(error) => {
write!(f, "QPACK Encoded Required Insert Count is invalid: {error}")
}
Self::DeltaBase(error) => write!(f, "QPACK Delta Base is invalid: {error}"),
Self::LengthOverflow => {
f.write_str("QPACK field-section prefix length overflows usize")
}
}
}
}
impl core::error::Error for QpackFieldSectionPrefixParseError {}
#[derive(Clone, Copy)]
pub(crate) struct QpackFieldSectionPrefixPlan {
encoded_required_insert_count: u64,
negative: bool,
delta_base: u64,
required_insert_count_len: usize,
encoded_len: usize,
}
impl QpackFieldSectionPrefixPlan {
pub(crate) const fn encoded_len(self) -> usize {
self.encoded_len
}
pub(crate) fn write(self, destination: &mut [u8]) {
if destination.len() != self.encoded_len {
return;
}
let (ric, delta) = destination.split_at_mut(self.required_insert_count_len);
write_canonical_prevalidated(ric, 8, 0, self.encoded_required_insert_count);
write_canonical_prevalidated(
delta,
7,
if self.negative { 0x80 } else { 0 },
self.delta_base,
);
}
}
pub(crate) fn plan_field_section_prefix(
encoded_required_insert_count: u64,
negative: bool,
delta_base: u64,
) -> Result<QpackFieldSectionPrefixPlan, QpackFieldSectionPrefixBuildError> {
if encoded_required_insert_count > QPACK_INTEGER_MAX {
return Err(QpackFieldSectionPrefixBuildError::RequiredInsertCount(
QpackIntegerBuildError::ValueTooLarge {
value: encoded_required_insert_count,
},
));
}
if delta_base > QPACK_INTEGER_MAX {
return Err(QpackFieldSectionPrefixBuildError::DeltaBase(
QpackIntegerBuildError::ValueTooLarge { value: delta_base },
));
}
let required_insert_count_len = canonical_encoded_len(encoded_required_insert_count, 8);
let delta_base_len = canonical_encoded_len(delta_base, 7);
let encoded_len = required_insert_count_len
.checked_add(delta_base_len)
.ok_or(QpackFieldSectionPrefixBuildError::RequiredLengthOverflow)?;
Ok(QpackFieldSectionPrefixPlan {
encoded_required_insert_count,
negative,
delta_base,
required_insert_count_len,
encoded_len,
})
}
pub struct QpackFieldSectionPrefixBuilder<'a> {
destination: &'a mut [u8],
encoded_required_insert_count: u64,
negative: bool,
delta_base: u64,
}
impl<'a> QpackFieldSectionPrefixBuilder<'a> {
pub fn new(
destination: &'a mut [u8],
encoded_required_insert_count: u64,
negative: bool,
delta_base: u64,
) -> Self {
Self {
destination,
encoded_required_insert_count,
negative,
delta_base,
}
}
pub fn build(self) -> Result<QpackFieldSectionPrefix<'a>, QpackFieldSectionPrefixBuildError> {
let plan = plan_field_section_prefix(
self.encoded_required_insert_count,
self.negative,
self.delta_base,
)?;
let required = plan.encoded_len();
if self.destination.len() < required {
return Err(QpackFieldSectionPrefixBuildError::BufferTooShort {
required,
available: self.destination.len(),
});
}
plan.write(&mut self.destination[..required]);
let bytes = &self.destination[..required];
let ric_len = plan.required_insert_count_len;
Ok(QpackFieldSectionPrefix {
bytes,
encoded_required_insert_count: integer_from_prevalidated(
&bytes[..ric_len],
8,
0,
self.encoded_required_insert_count,
),
negative: self.negative,
delta_base: integer_from_prevalidated(
&bytes[ric_len..],
7,
if self.negative { 0x80 } else { 0 },
self.delta_base,
),
})
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum QpackFieldSectionPrefixBuildError {
RequiredInsertCount(
#[doc = "The nested Required Insert Count failure."] QpackIntegerBuildError,
),
DeltaBase(#[doc = "The nested Delta Base failure."] QpackIntegerBuildError),
RequiredLengthOverflow,
BufferTooShort {
required: usize,
available: usize,
},
}
impl fmt::Display for QpackFieldSectionPrefixBuildError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::RequiredInsertCount(error) => write!(
f,
"QPACK Encoded Required Insert Count cannot be built: {error}"
),
Self::DeltaBase(error) => write!(f, "QPACK Delta Base cannot be built: {error}"),
Self::RequiredLengthOverflow => {
f.write_str("QPACK field-section prefix length overflows usize")
}
Self::BufferTooShort {
required,
available,
} => write!(
f,
"QPACK field-section prefix buffer is too short: need {required} bytes, have {available}"
),
}
}
}
impl core::error::Error for QpackFieldSectionPrefixBuildError {}