net_wire/qpack/
huffman.rs1use core::fmt;
4
5use crate::rfc7541_huffman;
6
7pub struct QpackHuffmanEncoder<'input, 'output> {
9 decoded: &'input [u8],
10 destination: &'output mut [u8],
11}
12
13impl<'input, 'output> QpackHuffmanEncoder<'input, 'output> {
14 pub fn new(decoded: &'input [u8], destination: &'output mut [u8]) -> Self {
16 Self {
17 decoded,
18 destination,
19 }
20 }
21
22 pub fn required_encoded_len(decoded: &[u8]) -> Result<usize, QpackHuffmanEncodeError> {
24 rfc7541_huffman::encoded_len(decoded).map_err(map_encode)
25 }
26
27 pub fn encode(self) -> Result<&'output [u8], QpackHuffmanEncodeError> {
29 let required = Self::required_encoded_len(self.decoded)?;
30 if self.destination.len() < required {
31 return Err(QpackHuffmanEncodeError::DestinationTooShort {
32 required,
33 available: self.destination.len(),
34 });
35 }
36 let output = &mut self.destination[..required];
37 rfc7541_huffman::encode_prevalidated(self.decoded, output);
38 Ok(output)
39 }
40}
41
42#[derive(Clone, Copy, Debug, Eq, PartialEq)]
44pub enum QpackHuffmanEncodeError {
45 EncodedBitLengthOverflow,
47 EncodedByteLengthOverflow,
49 DestinationTooShort {
51 required: usize,
53 available: usize,
55 },
56}
57
58impl fmt::Display for QpackHuffmanEncodeError {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 match self {
61 Self::EncodedBitLengthOverflow => {
62 f.write_str("QPACK Huffman encoded bit length overflows usize")
63 }
64 Self::EncodedByteLengthOverflow => {
65 f.write_str("QPACK Huffman encoded byte length overflows usize")
66 }
67 Self::DestinationTooShort {
68 required,
69 available,
70 } => write!(
71 f,
72 "QPACK Huffman destination is too short: need {required} bytes, have {available}"
73 ),
74 }
75 }
76}
77
78pub struct QpackHuffmanDecoder<'input, 'output> {
80 encoded: &'input [u8],
81 destination: &'output mut [u8],
82}
83
84impl<'input, 'output> QpackHuffmanDecoder<'input, 'output> {
85 pub fn new(encoded: &'input [u8], destination: &'output mut [u8]) -> Self {
87 Self {
88 encoded,
89 destination,
90 }
91 }
92
93 pub fn required_decoded_len(encoded: &[u8]) -> Result<usize, QpackHuffmanDecodeError> {
95 rfc7541_huffman::decoded_len(encoded).map_err(map_decode)
96 }
97
98 pub fn decode(self) -> Result<&'output [u8], QpackHuffmanDecodeError> {
100 let required = Self::required_decoded_len(self.encoded)?;
101 if self.destination.len() < required {
102 return Err(QpackHuffmanDecodeError::OutputTooShort {
103 required,
104 available: self.destination.len(),
105 });
106 }
107 rfc7541_huffman::decode_prevalidated(self.encoded, &mut self.destination[..required]);
108 Ok(&self.destination[..required])
109 }
110}
111
112#[derive(Clone, Copy, Debug, Eq, PartialEq)]
114pub enum QpackHuffmanDecodeError {
115 EosSymbol,
117 InvalidHuffmanCode,
119 InvalidPadding,
121 DecodedLengthOverflow,
123 OutputTooShort {
125 required: usize,
127 available: usize,
129 },
130}
131
132pub(crate) fn decode_prevalidated(encoded: &[u8], destination: &mut [u8]) {
134 rfc7541_huffman::decode_prevalidated(encoded, destination);
135}
136
137impl fmt::Display for QpackHuffmanDecodeError {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 match self {
140 Self::EosSymbol => f.write_str("QPACK Huffman data contains EOS"),
141 Self::InvalidHuffmanCode => f.write_str("QPACK Huffman data contains an invalid code"),
142 Self::InvalidPadding => {
143 f.write_str("QPACK Huffman data has invalid EOS-prefix padding")
144 }
145 Self::DecodedLengthOverflow => {
146 f.write_str("QPACK Huffman decoded length overflows usize")
147 }
148 Self::OutputTooShort {
149 required,
150 available,
151 } => write!(
152 f,
153 "QPACK Huffman output buffer is too short: need {required} bytes, have {available}"
154 ),
155 }
156 }
157}
158
159fn map_encode(error: rfc7541_huffman::EncodeError) -> QpackHuffmanEncodeError {
160 match error {
161 rfc7541_huffman::EncodeError::BitLengthOverflow => {
162 QpackHuffmanEncodeError::EncodedBitLengthOverflow
163 }
164 rfc7541_huffman::EncodeError::ByteLengthOverflow => {
165 QpackHuffmanEncodeError::EncodedByteLengthOverflow
166 }
167 }
168}
169
170fn map_decode(error: rfc7541_huffman::DecodeError) -> QpackHuffmanDecodeError {
171 match error {
172 rfc7541_huffman::DecodeError::EosSymbol => QpackHuffmanDecodeError::EosSymbol,
173 rfc7541_huffman::DecodeError::InvalidHuffmanCode => {
174 QpackHuffmanDecodeError::InvalidHuffmanCode
175 }
176 rfc7541_huffman::DecodeError::InvalidPadding => QpackHuffmanDecodeError::InvalidPadding,
177 rfc7541_huffman::DecodeError::DecodedLengthOverflow => {
178 QpackHuffmanDecodeError::DecodedLengthOverflow
179 }
180 }
181}