1use core::fmt;
4
5use crate::qpack::integer::{QpackInteger, QpackIntegerParseError};
6use crate::qpack::string::{QpackStringLiteral, QpackStringLiteralParseError};
7
8mod apply;
9mod builder;
10
11pub use apply::{
12 QpackEncoderInstructionApplier, QpackEncoderInstructionApplyError,
13 QpackEncoderInstructionApplyOutcome, QpackEncoderInstructionsApplyError,
14};
15pub use builder::{
16 QpackDuplicateBuilder, QpackEncoderInstructionBuildError, QpackInsertWithLiteralNameBuilder,
17 QpackInsertWithNameReferenceBuilder, QpackSetDynamicTableCapacityBuilder,
18};
19
20#[derive(Clone, Copy, Debug, Eq, PartialEq)]
22pub enum QpackEncoderInstruction<'a> {
23 SetDynamicTableCapacity(QpackSetDynamicTableCapacity<'a>),
25 InsertWithNameReference(QpackInsertWithNameReference<'a>),
27 InsertWithLiteralName(QpackInsertWithLiteralName<'a>),
29 Duplicate(QpackDuplicate<'a>),
31}
32
33impl<'a> QpackEncoderInstruction<'a> {
34 pub fn parse(bytes: &'a [u8]) -> Result<Self, QpackEncoderInstructionParseError> {
36 let first = *bytes
37 .first()
38 .ok_or(QpackEncoderInstructionParseError::DispatchIncomplete)?;
39 if first & 0xe0 == 0x20 {
40 let capacity = QpackInteger::parse(bytes, 5)
41 .map_err(QpackEncoderInstructionParseError::SetDynamicTableCapacity)?;
42 return Ok(Self::SetDynamicTableCapacity(
43 QpackSetDynamicTableCapacity {
44 bytes: capacity.as_bytes(),
45 capacity,
46 },
47 ));
48 }
49 if first & 0x80 != 0 {
50 let name_index = QpackInteger::parse(bytes, 6)
51 .map_err(QpackEncoderInstructionParseError::InsertWithNameReferenceNameIndex)?;
52 let value = QpackStringLiteral::parse(&bytes[name_index.as_bytes().len()..], 8)
53 .map_err(QpackEncoderInstructionParseError::InsertWithNameReferenceValue)?;
54 let end = name_index.as_bytes().len() + value.as_bytes().len();
55 return Ok(Self::InsertWithNameReference(
56 QpackInsertWithNameReference {
57 bytes: &bytes[..end],
58 is_static: first & 0x40 != 0,
59 name_index,
60 value,
61 },
62 ));
63 }
64 if first & 0xc0 == 0x40 {
65 let name = QpackStringLiteral::parse(bytes, 6)
66 .map_err(QpackEncoderInstructionParseError::InsertWithLiteralNameName)?;
67 let value = QpackStringLiteral::parse(&bytes[name.as_bytes().len()..], 8)
68 .map_err(QpackEncoderInstructionParseError::InsertWithLiteralNameValue)?;
69 let end = name.as_bytes().len() + value.as_bytes().len();
70 return Ok(Self::InsertWithLiteralName(QpackInsertWithLiteralName {
71 bytes: &bytes[..end],
72 name,
73 value,
74 }));
75 }
76 let index = QpackInteger::parse(bytes, 5)
77 .map_err(QpackEncoderInstructionParseError::DuplicateIndex)?;
78 Ok(Self::Duplicate(QpackDuplicate {
79 bytes: index.as_bytes(),
80 index,
81 }))
82 }
83
84 pub const fn as_bytes(self) -> &'a [u8] {
86 match self {
87 Self::SetDynamicTableCapacity(instruction) => instruction.as_bytes(),
88 Self::InsertWithNameReference(instruction) => instruction.as_bytes(),
89 Self::InsertWithLiteralName(instruction) => instruction.as_bytes(),
90 Self::Duplicate(instruction) => instruction.as_bytes(),
91 }
92 }
93}
94
95#[derive(Clone, Copy, Debug, Eq, PartialEq)]
97pub struct QpackSetDynamicTableCapacity<'a> {
98 bytes: &'a [u8],
99 capacity: QpackInteger<'a>,
100}
101
102impl<'a> QpackSetDynamicTableCapacity<'a> {
103 pub const fn as_bytes(self) -> &'a [u8] {
105 self.bytes
106 }
107
108 pub const fn capacity(self) -> QpackInteger<'a> {
110 self.capacity
111 }
112}
113
114#[derive(Clone, Copy, Debug, Eq, PartialEq)]
116pub struct QpackInsertWithNameReference<'a> {
117 bytes: &'a [u8],
118 is_static: bool,
119 name_index: QpackInteger<'a>,
120 value: QpackStringLiteral<'a>,
121}
122
123impl<'a> QpackInsertWithNameReference<'a> {
124 pub const fn as_bytes(self) -> &'a [u8] {
126 self.bytes
127 }
128
129 pub const fn is_static(self) -> bool {
131 self.is_static
132 }
133
134 pub const fn name_index(self) -> QpackInteger<'a> {
136 self.name_index
137 }
138
139 pub const fn value(self) -> QpackStringLiteral<'a> {
141 self.value
142 }
143}
144
145#[derive(Clone, Copy, Debug, Eq, PartialEq)]
147pub struct QpackInsertWithLiteralName<'a> {
148 bytes: &'a [u8],
149 name: QpackStringLiteral<'a>,
150 value: QpackStringLiteral<'a>,
151}
152
153impl<'a> QpackInsertWithLiteralName<'a> {
154 pub const fn as_bytes(self) -> &'a [u8] {
156 self.bytes
157 }
158
159 pub const fn name(self) -> QpackStringLiteral<'a> {
161 self.name
162 }
163
164 pub const fn value(self) -> QpackStringLiteral<'a> {
166 self.value
167 }
168}
169
170#[derive(Clone, Copy, Debug, Eq, PartialEq)]
172pub struct QpackDuplicate<'a> {
173 bytes: &'a [u8],
174 index: QpackInteger<'a>,
175}
176
177impl<'a> QpackDuplicate<'a> {
178 pub const fn as_bytes(self) -> &'a [u8] {
180 self.bytes
181 }
182
183 pub const fn index(self) -> QpackInteger<'a> {
185 self.index
186 }
187}
188
189#[derive(Clone, Copy, Debug, Eq, PartialEq)]
191pub enum QpackEncoderInstructionParseError {
192 DispatchIncomplete,
194 SetDynamicTableCapacity(#[doc = "The nested capacity-integer failure."] QpackIntegerParseError),
196 InsertWithNameReferenceNameIndex(
198 #[doc = "The nested name-index failure."] QpackIntegerParseError,
199 ),
200 InsertWithNameReferenceValue(
202 #[doc = "The nested value-string failure."] QpackStringLiteralParseError,
203 ),
204 InsertWithLiteralNameName(
206 #[doc = "The nested name-string failure."] QpackStringLiteralParseError,
207 ),
208 InsertWithLiteralNameValue(
210 #[doc = "The nested value-string failure."] QpackStringLiteralParseError,
211 ),
212 DuplicateIndex(#[doc = "The nested duplicate-index failure."] QpackIntegerParseError),
214}
215
216impl fmt::Display for QpackEncoderInstructionParseError {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 match self {
219 Self::DispatchIncomplete => {
220 f.write_str("QPACK encoder instruction input is incomplete")
221 }
222 Self::SetDynamicTableCapacity(error) => {
223 write!(f, "QPACK Set Dynamic Table Capacity is invalid: {error}")
224 }
225 Self::InsertWithNameReferenceNameIndex(error) => {
226 write!(
227 f,
228 "QPACK Insert With Name Reference name index is invalid: {error}"
229 )
230 }
231 Self::InsertWithNameReferenceValue(error) => {
232 write!(
233 f,
234 "QPACK Insert With Name Reference value is invalid: {error}"
235 )
236 }
237 Self::InsertWithLiteralNameName(error) => {
238 write!(f, "QPACK Insert With Literal Name name is invalid: {error}")
239 }
240 Self::InsertWithLiteralNameValue(error) => {
241 write!(
242 f,
243 "QPACK Insert With Literal Name value is invalid: {error}"
244 )
245 }
246 Self::DuplicateIndex(error) => write!(f, "QPACK Duplicate index is invalid: {error}"),
247 }
248 }
249}
250
251#[derive(Clone, Copy, Debug, Eq, PartialEq)]
253pub struct QpackEncoderInstructions<'a> {
254 bytes: &'a [u8],
255}
256
257impl<'a> QpackEncoderInstructions<'a> {
258 pub fn parse(bytes: &'a [u8]) -> Result<Self, QpackEncoderInstructionsParseError> {
260 let mut offset = 0usize;
261 while offset < bytes.len() {
262 let instruction = QpackEncoderInstruction::parse(&bytes[offset..])
263 .map_err(|error| QpackEncoderInstructionsParseError { offset, error })?;
264 offset += instruction.as_bytes().len();
265 }
266 Ok(Self { bytes })
267 }
268
269 pub const fn as_bytes(self) -> &'a [u8] {
271 self.bytes
272 }
273
274 pub const fn iter(self) -> QpackEncoderInstructionIter<'a> {
276 QpackEncoderInstructionIter {
277 remaining: self.bytes,
278 offset: 0,
279 failed: false,
280 }
281 }
282}
283
284#[derive(Clone, Copy, Debug, Eq, PartialEq)]
286pub struct QpackEncoderInstructionsParseError {
287 pub offset: usize,
289 pub error: QpackEncoderInstructionParseError,
291}
292
293impl fmt::Display for QpackEncoderInstructionsParseError {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 write!(
296 f,
297 "QPACK encoder instruction sequence is invalid at byte {}: {}",
298 self.offset, self.error
299 )
300 }
301}
302
303#[derive(Clone, Copy, Debug)]
305pub struct QpackEncoderInstructionIter<'a> {
306 remaining: &'a [u8],
307 offset: usize,
308 failed: bool,
309}
310
311impl<'a> Iterator for QpackEncoderInstructionIter<'a> {
312 type Item = Result<QpackEncoderInstruction<'a>, QpackEncoderInstructionsParseError>;
313
314 fn next(&mut self) -> Option<Self::Item> {
315 if self.failed || self.remaining.is_empty() {
316 return None;
317 }
318 match QpackEncoderInstruction::parse(self.remaining) {
319 Ok(instruction) => {
320 let consumed = instruction.as_bytes().len();
321 self.remaining = &self.remaining[consumed..];
322 self.offset += consumed;
323 Some(Ok(instruction))
324 }
325 Err(error) => {
326 self.failed = true;
327 Some(Err(QpackEncoderInstructionsParseError {
328 offset: self.offset,
329 error,
330 }))
331 }
332 }
333 }
334}
335
336impl core::iter::FusedIterator for QpackEncoderInstructionIter<'_> {}