net_wire/qpack/state/
blocked.rs1use core::fmt;
4use core::iter::FusedIterator;
5
6use crate::qpack::field::section::decode::QpackFieldSectionBlocked;
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct QpackBlockedStream {
11 occupied: bool,
12 stream_id: u64,
13 required_insert_count: u64,
14}
15
16impl QpackBlockedStream {
17 pub const EMPTY: Self = Self {
19 occupied: false,
20 stream_id: 0,
21 required_insert_count: 0,
22 };
23
24 pub const fn stream_id(self) -> u64 {
26 self.stream_id
27 }
28
29 pub const fn required_insert_count(self) -> u64 {
31 self.required_insert_count
32 }
33}
34
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
37pub enum QpackBlockedStreamsError {
38 MaximumBlockedStreamsExceedsStorage {
40 maximum: u64,
42 storage_capacity: usize,
44 },
45 BlockedStreamsLimitExceeded {
47 maximum: u64,
49 },
50}
51
52impl QpackBlockedStreamsError {
53 pub const fn is_decompression_failed(self) -> bool {
55 matches!(self, Self::BlockedStreamsLimitExceeded { .. })
56 }
57
58 pub const fn is_provisioning_error(self) -> bool {
60 matches!(self, Self::MaximumBlockedStreamsExceedsStorage { .. })
61 }
62}
63
64impl fmt::Display for QpackBlockedStreamsError {
65 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
66 match self {
67 Self::MaximumBlockedStreamsExceedsStorage {
68 maximum,
69 storage_capacity,
70 } => write!(
71 formatter,
72 "maximum blocked streams {maximum} exceeds storage capacity {storage_capacity}"
73 ),
74 Self::BlockedStreamsLimitExceeded { maximum } => {
75 write!(formatter, "blocked streams exceed maximum {maximum}")
76 }
77 }
78 }
79}
80
81impl core::error::Error for QpackBlockedStreamsError {}
82
83pub struct QpackBlockedStreams<'storage> {
92 records: &'storage mut [QpackBlockedStream],
93 maximum_blocked_streams: u64,
94 len: usize,
95}
96
97impl<'storage> QpackBlockedStreams<'storage> {
98 pub fn new(
103 records: &'storage mut [QpackBlockedStream],
104 maximum_blocked_streams: u64,
105 ) -> Result<Self, QpackBlockedStreamsError> {
106 let maximum = match usize::try_from(maximum_blocked_streams) {
107 Ok(maximum) => maximum,
108 Err(_) => {
109 return Err(
110 QpackBlockedStreamsError::MaximumBlockedStreamsExceedsStorage {
111 maximum: maximum_blocked_streams,
112 storage_capacity: records.len(),
113 },
114 );
115 }
116 };
117 if maximum > records.len() {
118 return Err(
119 QpackBlockedStreamsError::MaximumBlockedStreamsExceedsStorage {
120 maximum: maximum_blocked_streams,
121 storage_capacity: records.len(),
122 },
123 );
124 }
125 for record in records.iter_mut() {
126 *record = QpackBlockedStream::EMPTY;
127 }
128 Ok(Self {
129 records,
130 maximum_blocked_streams,
131 len: 0,
132 })
133 }
134
135 pub const fn maximum_blocked_streams(&self) -> u64 {
137 self.maximum_blocked_streams
138 }
139
140 pub const fn storage_capacity(&self) -> usize {
142 self.records.len()
143 }
144
145 pub const fn len(&self) -> usize {
147 self.len
148 }
149
150 pub const fn is_empty(&self) -> bool {
152 self.len == 0
153 }
154
155 pub fn contains(&self, stream_id: u64) -> bool {
157 self.records
158 .iter()
159 .any(|record| record.occupied && record.stream_id == stream_id)
160 }
161
162 pub fn is_blocked(&self, stream_id: u64, insert_count: u64) -> bool {
164 self.records.iter().any(|record| {
165 record.occupied
166 && record.stream_id == stream_id
167 && record.required_insert_count > insert_count
168 })
169 }
170
171 pub fn register(
176 &mut self,
177 stream_id: u64,
178 blocked: QpackFieldSectionBlocked,
179 ) -> Result<(), QpackBlockedStreamsError> {
180 for record in self.records.iter_mut() {
181 if record.occupied && record.stream_id == stream_id {
182 record.required_insert_count = record
183 .required_insert_count
184 .max(blocked.required_insert_count());
185 return Ok(());
186 }
187 }
188 if self.len >= self.maximum_blocked_streams as usize {
189 return Err(QpackBlockedStreamsError::BlockedStreamsLimitExceeded {
190 maximum: self.maximum_blocked_streams,
191 });
192 }
193 for record in self.records.iter_mut() {
194 if !record.occupied {
195 *record = QpackBlockedStream {
196 occupied: true,
197 stream_id,
198 required_insert_count: blocked.required_insert_count(),
199 };
200 self.len += 1;
201 return Ok(());
202 }
203 }
204 Err(QpackBlockedStreamsError::BlockedStreamsLimitExceeded {
205 maximum: self.maximum_blocked_streams,
206 })
207 }
208
209 pub fn remove(&mut self, stream_id: u64) -> bool {
211 for record in self.records.iter_mut() {
212 if record.occupied && record.stream_id == stream_id {
213 *record = QpackBlockedStream::EMPTY;
214 self.len -= 1;
215 return true;
216 }
217 }
218 false
219 }
220
221 pub fn ready(&self, insert_count: u64) -> QpackReadyBlockedStreamIter<'_> {
223 QpackReadyBlockedStreamIter {
224 remaining: self.records,
225 insert_count,
226 }
227 }
228}
229
230#[derive(Clone, Debug)]
232pub struct QpackReadyBlockedStreamIter<'a> {
233 remaining: &'a [QpackBlockedStream],
234 insert_count: u64,
235}
236
237impl Iterator for QpackReadyBlockedStreamIter<'_> {
238 type Item = QpackBlockedStream;
239
240 fn next(&mut self) -> Option<Self::Item> {
241 while let Some((record, remaining)) = self.remaining.split_first() {
242 self.remaining = remaining;
243 if record.occupied && record.required_insert_count <= self.insert_count {
244 return Some(*record);
245 }
246 }
247 None
248 }
249}
250
251impl FusedIterator for QpackReadyBlockedStreamIter<'_> {}