1use core::fmt;
4
5use super::{
6 QpackDuplicate, QpackInsertWithLiteralName, QpackInsertWithNameReference,
7 QpackSetDynamicTableCapacity,
8};
9use crate::qpack::integer::{
10 QPACK_INTEGER_MAX, QpackIntegerBuildError, canonical_encoded_len, integer_from_prevalidated,
11 write_canonical_prevalidated,
12};
13use crate::qpack::string::{
14 QpackStringLiteralBuildError, string_from_prevalidated, string_plan, write_string_prevalidated,
15};
16
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub enum QpackEncoderInstructionBuildError {
20 SetDynamicTableCapacity(#[doc = "The nested capacity-integer failure."] QpackIntegerBuildError),
22 InsertWithNameReferenceNameIndex(
24 #[doc = "The nested name-index failure."] QpackIntegerBuildError,
25 ),
26 InsertWithNameReferenceValue(
28 #[doc = "The nested value-string failure."] QpackStringLiteralBuildError,
29 ),
30 InsertWithLiteralNameName(
32 #[doc = "The nested name-string failure."] QpackStringLiteralBuildError,
33 ),
34 InsertWithLiteralNameValue(
36 #[doc = "The nested value-string failure."] QpackStringLiteralBuildError,
37 ),
38 DuplicateIndex(#[doc = "The nested duplicate-index failure."] QpackIntegerBuildError),
40 RequiredLengthOverflow,
42 BufferTooShort {
44 required: usize,
46 available: usize,
48 },
49}
50
51impl fmt::Display for QpackEncoderInstructionBuildError {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 match self {
54 Self::SetDynamicTableCapacity(error) => {
55 write!(
56 f,
57 "QPACK Set Dynamic Table Capacity cannot be built: {error}"
58 )
59 }
60 Self::InsertWithNameReferenceNameIndex(error) => {
61 write!(
62 f,
63 "QPACK Insert With Name Reference name index cannot be built: {error}"
64 )
65 }
66 Self::InsertWithNameReferenceValue(error) => {
67 write!(
68 f,
69 "QPACK Insert With Name Reference value cannot be built: {error}"
70 )
71 }
72 Self::InsertWithLiteralNameName(error) => {
73 write!(
74 f,
75 "QPACK Insert With Literal Name name cannot be built: {error}"
76 )
77 }
78 Self::InsertWithLiteralNameValue(error) => {
79 write!(
80 f,
81 "QPACK Insert With Literal Name value cannot be built: {error}"
82 )
83 }
84 Self::DuplicateIndex(error) => {
85 write!(f, "QPACK Duplicate index cannot be built: {error}")
86 }
87 Self::RequiredLengthOverflow => {
88 f.write_str("QPACK encoder instruction required length overflows usize")
89 }
90 Self::BufferTooShort {
91 required,
92 available,
93 } => write!(
94 f,
95 "QPACK encoder instruction buffer is too short: need {required} bytes, have {available}"
96 ),
97 }
98 }
99}
100
101pub struct QpackSetDynamicTableCapacityBuilder<'a> {
103 destination: &'a mut [u8],
104 capacity: u64,
105}
106
107impl<'a> QpackSetDynamicTableCapacityBuilder<'a> {
108 pub fn new(destination: &'a mut [u8], capacity: u64) -> Self {
110 Self {
111 destination,
112 capacity,
113 }
114 }
115
116 pub fn build(
118 self,
119 ) -> Result<QpackSetDynamicTableCapacity<'a>, QpackEncoderInstructionBuildError> {
120 let length = integer_length(self.capacity, 5)
121 .map_err(QpackEncoderInstructionBuildError::SetDynamicTableCapacity)?;
122 ensure_capacity(self.destination, length)?;
123 write_canonical_prevalidated(&mut self.destination[..length], 5, 0x20, self.capacity);
124 let bytes = &self.destination[..length];
125 Ok(QpackSetDynamicTableCapacity {
126 bytes,
127 capacity: integer_from_prevalidated(bytes, 5, 0x20, self.capacity),
128 })
129 }
130}
131
132pub struct QpackInsertWithNameReferenceBuilder<'a, 'value> {
134 destination: &'a mut [u8],
135 is_static: bool,
136 name_index: u64,
137 value_huffman: bool,
138 encoded_value: &'value [u8],
139}
140
141impl<'a, 'value> QpackInsertWithNameReferenceBuilder<'a, 'value> {
142 pub fn new(
144 destination: &'a mut [u8],
145 is_static: bool,
146 name_index: u64,
147 value_huffman: bool,
148 encoded_value: &'value [u8],
149 ) -> Self {
150 Self {
151 destination,
152 is_static,
153 name_index,
154 value_huffman,
155 encoded_value,
156 }
157 }
158
159 pub fn build(
161 self,
162 ) -> Result<QpackInsertWithNameReference<'a>, QpackEncoderInstructionBuildError> {
163 let name_length = integer_length(self.name_index, 6)
164 .map_err(QpackEncoderInstructionBuildError::InsertWithNameReferenceNameIndex)?;
165 let value_plan = string_plan(8, 0, self.value_huffman, self.encoded_value)
166 .map_err(QpackEncoderInstructionBuildError::InsertWithNameReferenceValue)?;
167 let required = checked_sum(name_length, value_plan.required())?;
168 ensure_capacity(self.destination, required)?;
169 let name_high_bits = 0x80 | if self.is_static { 0x40 } else { 0 };
170 let (name_destination, value_destination) =
171 self.destination[..required].split_at_mut(name_length);
172 write_canonical_prevalidated(name_destination, 6, name_high_bits, self.name_index);
173 write_string_prevalidated(value_destination, value_plan);
174 let bytes = &self.destination[..required];
175 let value = string_from_prevalidated(&bytes[name_length..], value_plan);
176 Ok(QpackInsertWithNameReference {
177 bytes,
178 is_static: self.is_static,
179 name_index: integer_from_prevalidated(
180 &bytes[..name_length],
181 6,
182 name_high_bits,
183 self.name_index,
184 ),
185 value,
186 })
187 }
188}
189
190pub struct QpackInsertWithLiteralNameBuilder<'a, 'name, 'value> {
192 destination: &'a mut [u8],
193 name_huffman: bool,
194 encoded_name: &'name [u8],
195 value_huffman: bool,
196 encoded_value: &'value [u8],
197}
198
199impl<'a, 'name, 'value> QpackInsertWithLiteralNameBuilder<'a, 'name, 'value> {
200 pub fn new(
202 destination: &'a mut [u8],
203 name_huffman: bool,
204 encoded_name: &'name [u8],
205 value_huffman: bool,
206 encoded_value: &'value [u8],
207 ) -> Self {
208 Self {
209 destination,
210 name_huffman,
211 encoded_name,
212 value_huffman,
213 encoded_value,
214 }
215 }
216
217 pub fn build(
219 self,
220 ) -> Result<QpackInsertWithLiteralName<'a>, QpackEncoderInstructionBuildError> {
221 let name_plan = string_plan(6, 0x40, self.name_huffman, self.encoded_name)
222 .map_err(QpackEncoderInstructionBuildError::InsertWithLiteralNameName)?;
223 let value_plan = string_plan(8, 0, self.value_huffman, self.encoded_value)
224 .map_err(QpackEncoderInstructionBuildError::InsertWithLiteralNameValue)?;
225 let required = checked_sum(name_plan.required(), value_plan.required())?;
226 ensure_capacity(self.destination, required)?;
227 let (name_destination, value_destination) =
228 self.destination[..required].split_at_mut(name_plan.required());
229 write_string_prevalidated(name_destination, name_plan);
230 write_string_prevalidated(value_destination, value_plan);
231 let bytes = &self.destination[..required];
232 let name = string_from_prevalidated(&bytes[..name_plan.required()], name_plan);
233 let value = string_from_prevalidated(&bytes[name_plan.required()..], value_plan);
234 Ok(QpackInsertWithLiteralName { bytes, name, value })
235 }
236}
237
238pub struct QpackDuplicateBuilder<'a> {
240 destination: &'a mut [u8],
241 index: u64,
242}
243
244impl<'a> QpackDuplicateBuilder<'a> {
245 pub fn new(destination: &'a mut [u8], index: u64) -> Self {
247 Self { destination, index }
248 }
249
250 pub fn build(self) -> Result<QpackDuplicate<'a>, QpackEncoderInstructionBuildError> {
252 let length = integer_length(self.index, 5)
253 .map_err(QpackEncoderInstructionBuildError::DuplicateIndex)?;
254 ensure_capacity(self.destination, length)?;
255 write_canonical_prevalidated(&mut self.destination[..length], 5, 0, self.index);
256 let bytes = &self.destination[..length];
257 Ok(QpackDuplicate {
258 bytes,
259 index: integer_from_prevalidated(bytes, 5, 0, self.index),
260 })
261 }
262}
263
264fn integer_length(value: u64, prefix_bits: u8) -> Result<usize, QpackIntegerBuildError> {
265 if value > QPACK_INTEGER_MAX {
266 return Err(QpackIntegerBuildError::ValueTooLarge { value });
267 }
268 Ok(canonical_encoded_len(value, prefix_bits))
269}
270
271fn checked_sum(left: usize, right: usize) -> Result<usize, QpackEncoderInstructionBuildError> {
272 left.checked_add(right)
273 .ok_or(QpackEncoderInstructionBuildError::RequiredLengthOverflow)
274}
275
276fn ensure_capacity(
277 destination: &[u8],
278 required: usize,
279) -> Result<(), QpackEncoderInstructionBuildError> {
280 if destination.len() < required {
281 return Err(QpackEncoderInstructionBuildError::BufferTooShort {
282 required,
283 available: destination.len(),
284 });
285 }
286 Ok(())
287}