use core::fmt;
use super::{QpackInsertCountIncrement, QpackSectionAcknowledgment, QpackStreamCancellation};
use crate::qpack::integer::{
QPACK_INTEGER_MAX, QpackIntegerBuildError, canonical_encoded_len, integer_from_prevalidated,
write_canonical_prevalidated,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum QpackDecoderInstructionBuildError {
SectionAcknowledgment(#[doc = "The nested stream-ID failure."] QpackIntegerBuildError),
StreamCancellation(#[doc = "The nested stream-ID failure."] QpackIntegerBuildError),
InsertCountIncrement(#[doc = "The nested increment failure."] QpackIntegerBuildError),
BufferTooShort {
required: usize,
available: usize,
},
}
impl fmt::Display for QpackDecoderInstructionBuildError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::SectionAcknowledgment(error) => {
write!(f, "QPACK Section Acknowledgment cannot be built: {error}")
}
Self::StreamCancellation(error) => {
write!(f, "QPACK Stream Cancellation cannot be built: {error}")
}
Self::InsertCountIncrement(error) => {
write!(f, "QPACK Insert Count Increment cannot be built: {error}")
}
Self::BufferTooShort {
required,
available,
} => write!(
f,
"QPACK decoder instruction buffer is too short: need {required} bytes, have {available}"
),
}
}
}
pub struct QpackSectionAcknowledgmentBuilder<'a> {
destination: &'a mut [u8],
stream_id: u64,
}
impl<'a> QpackSectionAcknowledgmentBuilder<'a> {
pub fn new(destination: &'a mut [u8], stream_id: u64) -> Self {
Self {
destination,
stream_id,
}
}
pub fn build(
self,
) -> Result<QpackSectionAcknowledgment<'a>, QpackDecoderInstructionBuildError> {
let length = integer_length(self.stream_id, 7)
.map_err(QpackDecoderInstructionBuildError::SectionAcknowledgment)?;
ensure_capacity(self.destination, length)?;
write_canonical_prevalidated(&mut self.destination[..length], 7, 0x80, self.stream_id);
let bytes = &self.destination[..length];
Ok(QpackSectionAcknowledgment {
bytes,
stream_id: integer_from_prevalidated(bytes, 7, 0x80, self.stream_id),
})
}
}
pub struct QpackStreamCancellationBuilder<'a> {
destination: &'a mut [u8],
stream_id: u64,
}
impl<'a> QpackStreamCancellationBuilder<'a> {
pub fn new(destination: &'a mut [u8], stream_id: u64) -> Self {
Self {
destination,
stream_id,
}
}
pub fn build(self) -> Result<QpackStreamCancellation<'a>, QpackDecoderInstructionBuildError> {
let length = integer_length(self.stream_id, 6)
.map_err(QpackDecoderInstructionBuildError::StreamCancellation)?;
ensure_capacity(self.destination, length)?;
write_canonical_prevalidated(&mut self.destination[..length], 6, 0x40, self.stream_id);
let bytes = &self.destination[..length];
Ok(QpackStreamCancellation {
bytes,
stream_id: integer_from_prevalidated(bytes, 6, 0x40, self.stream_id),
})
}
}
pub struct QpackInsertCountIncrementBuilder<'a> {
destination: &'a mut [u8],
increment: u64,
}
impl<'a> QpackInsertCountIncrementBuilder<'a> {
pub fn new(destination: &'a mut [u8], increment: u64) -> Self {
Self {
destination,
increment,
}
}
pub fn build(self) -> Result<QpackInsertCountIncrement<'a>, QpackDecoderInstructionBuildError> {
let length = integer_length(self.increment, 6)
.map_err(QpackDecoderInstructionBuildError::InsertCountIncrement)?;
ensure_capacity(self.destination, length)?;
write_canonical_prevalidated(&mut self.destination[..length], 6, 0, self.increment);
let bytes = &self.destination[..length];
Ok(QpackInsertCountIncrement {
bytes,
increment: integer_from_prevalidated(bytes, 6, 0, self.increment),
})
}
}
fn integer_length(value: u64, prefix_bits: u8) -> Result<usize, QpackIntegerBuildError> {
if value > QPACK_INTEGER_MAX {
return Err(QpackIntegerBuildError::ValueTooLarge { value });
}
Ok(canonical_encoded_len(value, prefix_bits))
}
fn ensure_capacity(
destination: &[u8],
required: usize,
) -> Result<(), QpackDecoderInstructionBuildError> {
if destination.len() < required {
return Err(QpackDecoderInstructionBuildError::BufferTooShort {
required,
available: destination.len(),
});
}
Ok(())
}