1use crate::settings::{
6 DEFAULT_HEADER_TABLE_SIZE, DEFAULT_INITIAL_WINDOW_SIZE, DEFAULT_MAX_FRAME_SIZE, MaxFrameSize,
7 WindowSize,
8};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct Limits {
13 max_concurrent_streams: Option<u32>,
14 initial_window_size: WindowSize,
15 max_frame_size: MaxFrameSize,
16 max_header_list_size: Option<u32>,
17 header_table_size: u32,
18 connection_window_size: WindowSize,
19 enable_connect_protocol: bool,
20 no_rfc7540_priorities: bool,
21 wt_initial_max_data: Option<u32>,
22 wt_initial_max_stream_data_uni: Option<u32>,
23 wt_initial_max_stream_data_bidi_local: Option<u32>,
24 wt_initial_max_streams_uni: Option<u32>,
25 wt_initial_max_streams_bidi: Option<u32>,
26 wt_initial_max_stream_data_bidi_remote: Option<u32>,
27}
28
29impl Limits {
30 pub const fn builder() -> LimitsBuilder {
32 LimitsBuilder {
33 max_concurrent_streams: Some(100),
34 initial_window_size: WindowSize::from_static(DEFAULT_INITIAL_WINDOW_SIZE),
35 max_frame_size: MaxFrameSize::from_static(DEFAULT_MAX_FRAME_SIZE),
36 max_header_list_size: Some(16384),
37 header_table_size: DEFAULT_HEADER_TABLE_SIZE,
38 connection_window_size: WindowSize::from_static(DEFAULT_INITIAL_WINDOW_SIZE),
39 enable_connect_protocol: false,
40 no_rfc7540_priorities: false,
41 wt_initial_max_data: None,
42 wt_initial_max_stream_data_uni: None,
43 wt_initial_max_stream_data_bidi_local: None,
44 wt_initial_max_streams_uni: None,
45 wt_initial_max_streams_bidi: None,
46 wt_initial_max_stream_data_bidi_remote: None,
47 }
48 }
49
50 #[must_use]
52 pub const fn max_concurrent_streams(&self) -> Option<u32> {
53 self.max_concurrent_streams
54 }
55
56 #[must_use]
58 pub const fn initial_window_size(&self) -> WindowSize {
59 self.initial_window_size
60 }
61
62 #[must_use]
64 pub const fn max_frame_size(&self) -> MaxFrameSize {
65 self.max_frame_size
66 }
67
68 #[must_use]
70 pub const fn max_header_list_size(&self) -> Option<u32> {
71 self.max_header_list_size
72 }
73
74 #[must_use]
76 pub const fn header_table_size(&self) -> u32 {
77 self.header_table_size
78 }
79
80 #[must_use]
82 pub const fn connection_window_size(&self) -> WindowSize {
83 self.connection_window_size
84 }
85
86 #[must_use]
88 pub const fn enable_connect_protocol(&self) -> bool {
89 self.enable_connect_protocol
90 }
91
92 #[must_use]
94 pub const fn no_rfc7540_priorities(&self) -> bool {
95 self.no_rfc7540_priorities
96 }
97
98 #[must_use]
100 pub const fn wt_initial_max_data(&self) -> Option<u32> {
101 self.wt_initial_max_data
102 }
103
104 #[must_use]
106 pub const fn wt_initial_max_stream_data_uni(&self) -> Option<u32> {
107 self.wt_initial_max_stream_data_uni
108 }
109
110 #[must_use]
112 pub const fn wt_initial_max_stream_data_bidi_local(&self) -> Option<u32> {
113 self.wt_initial_max_stream_data_bidi_local
114 }
115
116 #[must_use]
118 pub const fn wt_initial_max_streams_uni(&self) -> Option<u32> {
119 self.wt_initial_max_streams_uni
120 }
121
122 #[must_use]
124 pub const fn wt_initial_max_streams_bidi(&self) -> Option<u32> {
125 self.wt_initial_max_streams_bidi
126 }
127
128 #[must_use]
130 pub const fn wt_initial_max_stream_data_bidi_remote(&self) -> Option<u32> {
131 self.wt_initial_max_stream_data_bidi_remote
132 }
133}
134
135impl Default for Limits {
136 fn default() -> Self {
137 Limits::builder()
138 .build()
139 .expect("default Limits values are always valid")
140 }
141}
142
143#[derive(Debug, Clone, PartialEq, Eq)]
145pub struct LimitsBuilder {
146 max_concurrent_streams: Option<u32>,
147 initial_window_size: WindowSize,
148 max_frame_size: MaxFrameSize,
149 max_header_list_size: Option<u32>,
150 header_table_size: u32,
151 connection_window_size: WindowSize,
152 enable_connect_protocol: bool,
153 no_rfc7540_priorities: bool,
154 wt_initial_max_data: Option<u32>,
155 wt_initial_max_stream_data_uni: Option<u32>,
156 wt_initial_max_stream_data_bidi_local: Option<u32>,
157 wt_initial_max_streams_uni: Option<u32>,
158 wt_initial_max_streams_bidi: Option<u32>,
159 wt_initial_max_stream_data_bidi_remote: Option<u32>,
160}
161
162impl LimitsBuilder {
163 #[must_use]
165 pub const fn max_concurrent_streams(mut self, max: Option<u32>) -> Self {
166 self.max_concurrent_streams = max;
167 self
168 }
169
170 #[must_use]
172 pub const fn initial_window_size(mut self, size: WindowSize) -> Self {
173 self.initial_window_size = size;
174 self
175 }
176
177 #[must_use]
179 pub const fn max_frame_size(mut self, size: MaxFrameSize) -> Self {
180 self.max_frame_size = size;
181 self
182 }
183
184 #[must_use]
186 pub const fn max_header_list_size(mut self, size: Option<u32>) -> Self {
187 self.max_header_list_size = size;
188 self
189 }
190
191 #[must_use]
193 pub const fn header_table_size(mut self, size: u32) -> Self {
194 self.header_table_size = size;
195 self
196 }
197
198 #[must_use]
205 pub const fn connection_window_size(mut self, size: WindowSize) -> Self {
206 assert!(
207 size.get() >= DEFAULT_INITIAL_WINDOW_SIZE,
208 "LimitsBuilder::connection_window_size: size must be >= DEFAULT_INITIAL_WINDOW_SIZE (RFC 9113 §6.9.2)"
209 );
210 self.connection_window_size = size;
211 self
212 }
213
214 #[must_use]
216 pub const fn enable_connect_protocol(mut self, enable: bool) -> Self {
217 self.enable_connect_protocol = enable;
218 self
219 }
220
221 #[must_use]
223 pub const fn no_rfc7540_priorities(mut self, enable: bool) -> Self {
224 self.no_rfc7540_priorities = enable;
225 self
226 }
227
228 #[must_use]
230 pub const fn webtransport(
231 mut self,
232 max_data: Option<u32>,
233 max_stream_data_uni: Option<u32>,
234 max_stream_data_bidi_local: Option<u32>,
235 max_streams_uni: Option<u32>,
236 max_streams_bidi: Option<u32>,
237 max_stream_data_bidi_remote: Option<u32>,
238 ) -> Self {
239 self.wt_initial_max_data = max_data;
240 self.wt_initial_max_stream_data_uni = max_stream_data_uni;
241 self.wt_initial_max_stream_data_bidi_local = max_stream_data_bidi_local;
242 self.wt_initial_max_streams_uni = max_streams_uni;
243 self.wt_initial_max_streams_bidi = max_streams_bidi;
244 self.wt_initial_max_stream_data_bidi_remote = max_stream_data_bidi_remote;
245 self
246 }
247
248 pub fn build(self) -> Result<Limits, LimitsError> {
255 if !self.enable_connect_protocol && self.has_webtransport_settings() {
256 return Err(LimitsError::WebtransportRequiresConnectProtocol);
257 }
258
259 Ok(Limits {
260 max_concurrent_streams: self.max_concurrent_streams,
261 initial_window_size: self.initial_window_size,
262 max_frame_size: self.max_frame_size,
263 max_header_list_size: self.max_header_list_size,
264 header_table_size: self.header_table_size,
265 connection_window_size: self.connection_window_size,
266 enable_connect_protocol: self.enable_connect_protocol,
267 no_rfc7540_priorities: self.no_rfc7540_priorities,
268 wt_initial_max_data: self.wt_initial_max_data,
269 wt_initial_max_stream_data_uni: self.wt_initial_max_stream_data_uni,
270 wt_initial_max_stream_data_bidi_local: self.wt_initial_max_stream_data_bidi_local,
271 wt_initial_max_streams_uni: self.wt_initial_max_streams_uni,
272 wt_initial_max_streams_bidi: self.wt_initial_max_streams_bidi,
273 wt_initial_max_stream_data_bidi_remote: self.wt_initial_max_stream_data_bidi_remote,
274 })
275 }
276
277 pub const fn build_static(self) -> Limits {
279 if !self.enable_connect_protocol && self.has_webtransport_settings() {
280 panic!(
281 "LimitsBuilder::build_static: WebTransport settings require enable_connect_protocol = true"
282 );
283 }
284
285 Limits {
286 max_concurrent_streams: self.max_concurrent_streams,
287 initial_window_size: self.initial_window_size,
288 max_frame_size: self.max_frame_size,
289 max_header_list_size: self.max_header_list_size,
290 header_table_size: self.header_table_size,
291 connection_window_size: self.connection_window_size,
292 enable_connect_protocol: self.enable_connect_protocol,
293 no_rfc7540_priorities: self.no_rfc7540_priorities,
294 wt_initial_max_data: self.wt_initial_max_data,
295 wt_initial_max_stream_data_uni: self.wt_initial_max_stream_data_uni,
296 wt_initial_max_stream_data_bidi_local: self.wt_initial_max_stream_data_bidi_local,
297 wt_initial_max_streams_uni: self.wt_initial_max_streams_uni,
298 wt_initial_max_streams_bidi: self.wt_initial_max_streams_bidi,
299 wt_initial_max_stream_data_bidi_remote: self.wt_initial_max_stream_data_bidi_remote,
300 }
301 }
302
303 const fn has_webtransport_settings(&self) -> bool {
304 self.wt_initial_max_data.is_some()
305 || self.wt_initial_max_stream_data_uni.is_some()
306 || self.wt_initial_max_stream_data_bidi_local.is_some()
307 || self.wt_initial_max_streams_uni.is_some()
308 || self.wt_initial_max_streams_bidi.is_some()
309 || self.wt_initial_max_stream_data_bidi_remote.is_some()
310 }
311}
312
313#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
315pub enum LimitsError {
316 WebtransportRequiresConnectProtocol,
322}
323
324impl std::fmt::Display for LimitsError {
325 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
326 match self {
327 Self::WebtransportRequiresConnectProtocol => write!(
328 f,
329 "WebTransport settings require enable_connect_protocol = true"
330 ),
331 }
332 }
333}
334
335impl std::error::Error for LimitsError {}