1use core::fmt;
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub struct HpackInteger<'a> {
8 bytes: &'a [u8],
9 prefix_bits: u8,
10 value: u64,
11 high_bits: u8,
12}
13
14impl<'a> HpackInteger<'a> {
15 pub fn parse(bytes: &'a [u8], prefix_bits: u8) -> Result<Self, HpackIntegerParseError> {
17 let prefix_mask = prefix_mask(prefix_bits)?;
18 let first = *bytes.first().ok_or(HpackIntegerParseError::Incomplete {
19 required: 1,
20 available: 0,
21 })?;
22 let prefix_value = first & prefix_mask;
23 let high_bits = first & !prefix_mask;
24
25 if prefix_value < prefix_mask {
26 return Ok(Self {
27 bytes: &bytes[..1],
28 prefix_bits,
29 value: u64::from(prefix_value),
30 high_bits,
31 });
32 }
33
34 let mut value = u64::from(prefix_mask);
35 let mut shift = 0u32;
36 let mut index = 1usize;
37 loop {
38 let octet = *bytes.get(index).ok_or(HpackIntegerParseError::Incomplete {
39 required: index
40 .checked_add(1)
41 .ok_or(HpackIntegerParseError::Overflow)?,
42 available: bytes.len(),
43 })?;
44 if shift >= u64::BITS {
45 return Err(HpackIntegerParseError::Overflow);
46 }
47 let contribution = u64::from(octet & 0x7f)
48 .checked_mul(1u64 << shift)
49 .ok_or(HpackIntegerParseError::Overflow)?;
50 value = value
51 .checked_add(contribution)
52 .ok_or(HpackIntegerParseError::Overflow)?;
53 index = index
54 .checked_add(1)
55 .ok_or(HpackIntegerParseError::Overflow)?;
56 if octet & 0x80 == 0 {
57 return Ok(Self {
58 bytes: &bytes[..index],
59 prefix_bits,
60 value,
61 high_bits,
62 });
63 }
64 shift = shift
65 .checked_add(7)
66 .ok_or(HpackIntegerParseError::Overflow)?;
67 }
68 }
69
70 pub const fn value(self) -> u64 {
72 self.value
73 }
74
75 pub const fn as_bytes(self) -> &'a [u8] {
77 self.bytes
78 }
79
80 pub const fn prefix_bits(self) -> u8 {
82 self.prefix_bits
83 }
84
85 pub const fn high_bits(self) -> u8 {
87 self.high_bits
88 }
89}
90
91pub(crate) fn canonical_encoded_len(value: u64, prefix_mask: u8) -> usize {
92 encoded_len(value, prefix_mask)
93}
94
95pub(crate) fn canonical_integer<'a>(
96 bytes: &'a [u8],
97 prefix_bits: u8,
98 high_bits: u8,
99 value: u64,
100) -> HpackInteger<'a> {
101 HpackInteger {
102 bytes,
103 prefix_bits,
104 value,
105 high_bits,
106 }
107}
108
109#[derive(Clone, Copy, Debug, Eq, PartialEq)]
111pub enum HpackIntegerParseError {
112 InvalidPrefixBits {
114 prefix_bits: u8,
116 },
117 Incomplete {
119 required: usize,
121 available: usize,
123 },
124 Overflow,
126}
127
128impl fmt::Display for HpackIntegerParseError {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 match self {
131 Self::InvalidPrefixBits { prefix_bits } => {
132 write!(
133 f,
134 "HPACK integer prefix width must be 1 through 8, got {prefix_bits}"
135 )
136 }
137 Self::Incomplete {
138 required,
139 available,
140 } => write!(
141 f,
142 "HPACK integer input is incomplete: need {required} bytes, have {available}"
143 ),
144 Self::Overflow => f.write_str("HPACK integer exceeds u64"),
145 }
146 }
147}
148
149pub struct HpackIntegerBuilder<'a> {
151 destination: &'a mut [u8],
152 prefix_bits: u8,
153 high_bits: u8,
154 value: u64,
155}
156
157impl<'a> HpackIntegerBuilder<'a> {
158 pub fn new(destination: &'a mut [u8], prefix_bits: u8, high_bits: u8, value: u64) -> Self {
160 Self {
161 destination,
162 prefix_bits,
163 high_bits,
164 value,
165 }
166 }
167
168 pub fn build(self) -> Result<HpackInteger<'a>, HpackIntegerBuildError> {
170 let prefix_mask = prefix_mask(self.prefix_bits).map_err(|_| {
171 HpackIntegerBuildError::InvalidPrefixBits {
172 prefix_bits: self.prefix_bits,
173 }
174 })?;
175 if self.high_bits & prefix_mask != 0 {
176 return Err(HpackIntegerBuildError::HighBitsOverlap {
177 high_bits: self.high_bits,
178 prefix_bits: self.prefix_bits,
179 });
180 }
181
182 let required = encoded_len(self.value, prefix_mask);
183 if self.destination.len() < required {
184 return Err(HpackIntegerBuildError::BufferTooShort {
185 required,
186 available: self.destination.len(),
187 });
188 }
189
190 Ok(write_canonical(
191 &mut self.destination[..required],
192 self.prefix_bits,
193 prefix_mask,
194 self.high_bits,
195 self.value,
196 ))
197 }
198}
199
200#[derive(Clone, Copy, Debug, Eq, PartialEq)]
202pub enum HpackIntegerBuildError {
203 InvalidPrefixBits {
205 prefix_bits: u8,
207 },
208 HighBitsOverlap {
210 high_bits: u8,
212 prefix_bits: u8,
214 },
215 BufferTooShort {
217 required: usize,
219 available: usize,
221 },
222}
223
224impl fmt::Display for HpackIntegerBuildError {
225 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226 match self {
227 Self::InvalidPrefixBits { prefix_bits } => {
228 write!(
229 f,
230 "HPACK integer prefix width must be 1 through 8, got {prefix_bits}"
231 )
232 }
233 Self::HighBitsOverlap {
234 high_bits,
235 prefix_bits,
236 } => write!(
237 f,
238 "HPACK integer high bits {high_bits:#04x} overlap the {prefix_bits}-bit prefix"
239 ),
240 Self::BufferTooShort {
241 required,
242 available,
243 } => write!(
244 f,
245 "HPACK integer buffer is too short: need {required} bytes, have {available}"
246 ),
247 }
248 }
249}
250
251fn write_canonical<'a>(
252 bytes: &'a mut [u8],
253 prefix_bits: u8,
254 prefix_mask: u8,
255 high_bits: u8,
256 value: u64,
257) -> HpackInteger<'a> {
258 if value < u64::from(prefix_mask) {
259 bytes[0] = high_bits | value as u8;
260 } else {
261 bytes[0] = high_bits | prefix_mask;
262 let mut remaining = value - u64::from(prefix_mask);
263 let mut index = 1usize;
264 while remaining >= 0x80 {
265 bytes[index] = (remaining as u8 & 0x7f) | 0x80;
266 remaining >>= 7;
267 index += 1;
268 }
269 bytes[index] = remaining as u8;
270 }
271
272 canonical_integer(bytes, prefix_bits, high_bits, value)
273}
274
275pub(crate) fn write_canonical_for_valid_prefix(
276 bytes: &mut [u8],
277 prefix_bits: u8,
278 prefix_mask: u8,
279 high_bits: u8,
280 value: u64,
281) {
282 let required = canonical_encoded_len(value, prefix_mask);
283 debug_assert_eq!(bytes.len(), required);
284 let _ = write_canonical(bytes, prefix_bits, prefix_mask, high_bits, value);
285}
286
287fn prefix_mask(prefix_bits: u8) -> Result<u8, HpackIntegerParseError> {
288 match prefix_bits {
289 1..=7 => Ok((1u8 << prefix_bits) - 1),
290 8 => Ok(u8::MAX),
291 _ => Err(HpackIntegerParseError::InvalidPrefixBits { prefix_bits }),
292 }
293}
294
295fn encoded_len(value: u64, prefix_mask: u8) -> usize {
296 if value < u64::from(prefix_mask) {
297 return 1;
298 }
299
300 let mut required = 2usize;
301 let mut remaining = value - u64::from(prefix_mask);
302 while remaining >= 0x80 {
303 required += 1;
304 remaining >>= 7;
305 }
306 required
307}