use core::fmt;
use crate::rfc7541_huffman;
pub struct HpackHuffmanEncoder<'input, 'output> {
decoded: &'input [u8],
destination: &'output mut [u8],
}
impl<'input, 'output> HpackHuffmanEncoder<'input, 'output> {
pub fn new(decoded: &'input [u8], destination: &'output mut [u8]) -> Self {
Self {
decoded,
destination,
}
}
pub fn required_encoded_len(decoded: &[u8]) -> Result<usize, HpackHuffmanEncodeError> {
rfc7541_huffman::encoded_len(decoded).map_err(map_encode_error)
}
pub fn encode(self) -> Result<&'output [u8], HpackHuffmanEncodeError> {
let required = Self::required_encoded_len(self.decoded)?;
if self.destination.len() < required {
return Err(HpackHuffmanEncodeError::DestinationTooShort {
required,
available: self.destination.len(),
});
}
let destination = &mut self.destination[..required];
Self::encode_prevalidated(self.decoded, destination);
Ok(destination)
}
pub(super) fn encode_prevalidated(decoded: &[u8], destination: &mut [u8]) {
rfc7541_huffman::encode_prevalidated(decoded, destination);
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum HpackHuffmanEncodeError {
EncodedBitLengthOverflow,
EncodedByteLengthOverflow,
DestinationTooShort {
required: usize,
available: usize,
},
}
impl fmt::Display for HpackHuffmanEncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::EncodedBitLengthOverflow => {
f.write_str("HPACK Huffman encoded bit length overflows usize")
}
Self::EncodedByteLengthOverflow => {
f.write_str("HPACK Huffman encoded byte length overflows usize")
}
Self::DestinationTooShort {
required,
available,
} => write!(
f,
"HPACK Huffman destination is too short: need {required} bytes, have {available}"
),
}
}
}
pub struct HpackHuffmanDecoder<'input, 'output> {
encoded: &'input [u8],
destination: &'output mut [u8],
}
impl<'input, 'output> HpackHuffmanDecoder<'input, 'output> {
pub fn new(encoded: &'input [u8], destination: &'output mut [u8]) -> Self {
Self {
encoded,
destination,
}
}
pub fn required_decoded_len(encoded: &[u8]) -> Result<usize, HpackHuffmanDecodeError> {
rfc7541_huffman::decoded_len(encoded).map_err(map_decode_error)
}
pub fn decode(self) -> Result<&'output [u8], HpackHuffmanDecodeError> {
let required = Self::required_decoded_len(self.encoded)?;
if self.destination.len() < required {
return Err(HpackHuffmanDecodeError::OutputTooShort {
required,
available: self.destination.len(),
});
}
rfc7541_huffman::decode_prevalidated(self.encoded, &mut self.destination[..required]);
Ok(&self.destination[..required])
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum HpackHuffmanDecodeError {
EosSymbol,
InvalidHuffmanCode,
InvalidPadding,
DecodedLengthOverflow,
OutputTooShort {
required: usize,
available: usize,
},
}
impl fmt::Display for HpackHuffmanDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::EosSymbol => f.write_str("HPACK Huffman data contains EOS"),
Self::InvalidHuffmanCode => f.write_str("HPACK Huffman data contains an invalid code"),
Self::InvalidPadding => {
f.write_str("HPACK Huffman data has invalid EOS-prefix padding")
}
Self::DecodedLengthOverflow => {
f.write_str("HPACK Huffman decoded length overflows usize")
}
Self::OutputTooShort {
required,
available,
} => write!(
f,
"HPACK Huffman output buffer is too short: need {required} bytes, have {available}"
),
}
}
}
fn map_encode_error(error: rfc7541_huffman::EncodeError) -> HpackHuffmanEncodeError {
match error {
rfc7541_huffman::EncodeError::BitLengthOverflow => {
HpackHuffmanEncodeError::EncodedBitLengthOverflow
}
rfc7541_huffman::EncodeError::ByteLengthOverflow => {
HpackHuffmanEncodeError::EncodedByteLengthOverflow
}
}
}
fn map_decode_error(error: rfc7541_huffman::DecodeError) -> HpackHuffmanDecodeError {
match error {
rfc7541_huffman::DecodeError::EosSymbol => HpackHuffmanDecodeError::EosSymbol,
rfc7541_huffman::DecodeError::InvalidHuffmanCode => {
HpackHuffmanDecodeError::InvalidHuffmanCode
}
rfc7541_huffman::DecodeError::InvalidPadding => HpackHuffmanDecodeError::InvalidPadding,
rfc7541_huffman::DecodeError::DecodedLengthOverflow => {
HpackHuffmanDecodeError::DecodedLengthOverflow
}
}
}