1use crate::error::WireError;
23use crate::frame_type::FrameType;
24use crate::varint;
25
26const FLAG_CONTROL: u8 = 0b1000_0000;
30const FLAG_PRIORITY: u8 = 0b0100_0000;
32const FLAG_ENCRYPTED: u8 = 0b0010_0000;
34const _FLAG_RESERVED: u8 = 0b0001_0000;
36const TYPE_MASK: u8 = 0x0F;
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
41pub struct FrameFlags {
42 pub control: bool,
44 pub priority: bool,
46 pub encrypted: bool,
48}
49
50impl FrameFlags {
51 #[inline]
53 const fn to_bits(self) -> u8 {
54 let mut bits = 0u8;
55 if self.control { bits |= FLAG_CONTROL; }
56 if self.priority { bits |= FLAG_PRIORITY; }
57 if self.encrypted { bits |= FLAG_ENCRYPTED; }
58 bits
59 }
60
61 #[inline]
63 const fn from_bits(byte: u8) -> Self {
64 Self {
65 control: byte & FLAG_CONTROL != 0,
66 priority: byte & FLAG_PRIORITY != 0,
67 encrypted: byte & FLAG_ENCRYPTED != 0,
68 }
69 }
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct FrameHeader {
79 pub frame_type: FrameType,
81 pub flags: FrameFlags,
83 pub channel_id: u32,
85 pub stream_id: u64,
87 pub payload_len: u64,
89}
90
91impl FrameHeader {
92 #[inline]
94 pub const fn data(channel_id: u32, payload_len: u64) -> Self {
95 Self {
96 frame_type: FrameType::Data,
97 flags: FrameFlags { control: false, priority: false, encrypted: false },
98 channel_id,
99 stream_id: 0,
100 payload_len,
101 }
102 }
103
104 #[inline]
106 pub const fn control(frame_type: FrameType) -> Self {
107 Self {
108 frame_type,
109 flags: FrameFlags { control: true, priority: false, encrypted: false },
110 channel_id: 0,
111 stream_id: 0,
112 payload_len: 0,
113 }
114 }
115
116 #[inline]
118 pub const fn with_encrypted(mut self) -> Self {
119 self.flags.encrypted = true;
120 self
121 }
122
123 #[inline]
125 pub const fn with_priority(mut self) -> Self {
126 self.flags.priority = true;
127 self
128 }
129
130 #[inline]
132 pub const fn with_stream(mut self, stream_id: u64) -> Self {
133 self.stream_id = stream_id;
134 self
135 }
136
137 #[inline]
139 pub const fn encoded_len(&self) -> usize {
140 1 + varint::encoded_len(self.channel_id as u64)
142 + varint::encoded_len(self.stream_id)
143 + varint::encoded_len(self.payload_len)
144 }
145
146 pub fn encode(&self, buf: &mut [u8]) -> Result<usize, WireError> {
150 let needed = self.encoded_len();
151 if buf.len() < needed {
152 return Err(WireError::BufferTooSmall { needed, available: buf.len() });
153 }
154
155 let mut offset = 0;
156
157 buf[0] = self.flags.to_bits() | (self.frame_type as u8 & TYPE_MASK);
159 offset += 1;
160
161 offset += varint::encode(self.channel_id as u64, &mut buf[offset..])?;
163
164 offset += varint::encode(self.stream_id, &mut buf[offset..])?;
166
167 offset += varint::encode(self.payload_len, &mut buf[offset..])?;
169
170 debug_assert_eq!(offset, needed);
171 Ok(offset)
172 }
173
174 pub fn decode(buf: &[u8]) -> Result<(Self, usize), WireError> {
182 if buf.is_empty() {
183 return Err(WireError::Incomplete { needed_min: 4, available: 0 });
184 }
185
186 let byte0 = buf[0];
187 let mut offset = 1;
188
189 let flags = FrameFlags::from_bits(byte0);
191
192 let frame_type = FrameType::from_u8(byte0 & TYPE_MASK)?;
194
195 let (channel_raw, n) = varint::decode(&buf[offset..]).map_err(|e| match e {
197 WireError::Incomplete { needed_min, .. } => WireError::Incomplete {
198 needed_min: offset + needed_min,
199 available: buf.len(),
200 },
201 other => other,
202 })?;
203 offset += n;
204
205 let (stream_id, n) = varint::decode(&buf[offset..]).map_err(|e| match e {
207 WireError::Incomplete { needed_min, .. } => WireError::Incomplete {
208 needed_min: offset + needed_min,
209 available: buf.len(),
210 },
211 other => other,
212 })?;
213 offset += n;
214
215 let (payload_len, n) = varint::decode(&buf[offset..]).map_err(|e| match e {
217 WireError::Incomplete { needed_min, .. } => WireError::Incomplete {
218 needed_min: offset + needed_min,
219 available: buf.len(),
220 },
221 other => other,
222 })?;
223 offset += n;
224
225 Ok((
226 Self {
227 frame_type,
228 flags,
229 channel_id: channel_raw as u32,
230 stream_id,
231 payload_len,
232 },
233 offset,
234 ))
235 }
236}
237
238impl core::fmt::Display for FrameHeader {
239 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
240 write!(
241 f,
242 "[{}] ch={} stream={} len={} flags=[{}{}{}]",
243 self.frame_type,
244 self.channel_id,
245 self.stream_id,
246 self.payload_len,
247 if self.flags.control { "C" } else { "" },
248 if self.flags.priority { "P" } else { "" },
249 if self.flags.encrypted { "E" } else { "" },
250 )
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 extern crate alloc;
257 use alloc::format;
258 use super::*;
259
260 #[test]
261 fn minimal_data_header() {
262 let h = FrameHeader::data(0, 0);
264 let mut buf = [0u8; 32];
265 let n = h.encode(&mut buf).unwrap();
266 assert_eq!(n, 4, "minimum header should be 4 bytes");
267 assert_eq!(buf[0] & TYPE_MASK, 0x00); assert_eq!(buf[0] & 0xF0, 0x00); let (decoded, consumed) = FrameHeader::decode(&buf[..n]).unwrap();
271 assert_eq!(decoded, h);
272 assert_eq!(consumed, n);
273 }
274
275 #[test]
276 fn data_with_flags() {
277 let h = FrameHeader::data(1, 100)
278 .with_encrypted()
279 .with_priority()
280 .with_stream(42);
281
282 let mut buf = [0u8; 32];
283 let n = h.encode(&mut buf).unwrap();
284
285 assert_eq!(buf[0], 0x60);
287
288 let (decoded, consumed) = FrameHeader::decode(&buf[..n]).unwrap();
289 assert_eq!(decoded, h);
290 assert_eq!(consumed, n);
291 }
292
293 #[test]
294 fn control_ping() {
295 let h = FrameHeader::control(FrameType::Ping);
296 let mut buf = [0u8; 32];
297 let n = h.encode(&mut buf).unwrap();
298
299 assert_eq!(buf[0], 0x84);
301 assert_eq!(n, 4); let (decoded, _) = FrameHeader::decode(&buf[..n]).unwrap();
304 assert!(decoded.flags.control);
305 assert_eq!(decoded.frame_type, FrameType::Ping);
306 }
307
308 #[test]
309 fn handshake_type() {
310 for ft in [FrameType::HandshakeInit, FrameType::HandshakeReply, FrameType::HandshakeComplete] {
311 let h = FrameHeader {
312 frame_type: ft,
313 flags: FrameFlags::default(),
314 channel_id: 0,
315 stream_id: 0,
316 payload_len: 128,
317 };
318 let mut buf = [0u8; 32];
319 let n = h.encode(&mut buf).unwrap();
320 let (decoded, _) = FrameHeader::decode(&buf[..n]).unwrap();
321 assert_eq!(decoded.frame_type, ft);
322 assert!(decoded.frame_type.is_handshake());
323 }
324 }
325
326 #[test]
327 fn large_values() {
328 let h = FrameHeader {
329 frame_type: FrameType::FileChunk,
330 flags: FrameFlags { control: false, priority: true, encrypted: true },
331 channel_id: 1_000_000,
332 stream_id: 9_999_999_999,
333 payload_len: 4_294_967_296, };
335 let mut buf = [0u8; 32];
336 let n = h.encode(&mut buf).unwrap();
337 let (decoded, consumed) = FrameHeader::decode(&buf[..n]).unwrap();
338 assert_eq!(decoded, h);
339 assert_eq!(consumed, n);
340 }
341
342 #[test]
343 fn encoded_len_accurate() {
344 let h = FrameHeader::data(42, 100).with_stream(12345);
345 assert_eq!(h.encoded_len(), h.encode(&mut [0u8; 32]).unwrap());
346 }
347
348 #[test]
349 fn incomplete_decode() {
350 let buf = [0x00, 0x00];
352 match FrameHeader::decode(&buf) {
353 Err(WireError::Incomplete { .. }) => {} other => panic!("expected Incomplete, got {other:?}"),
355 }
356 }
357
358 #[test]
359 fn unknown_type_rejected() {
360 let buf = [0x0F, 0x00, 0x00, 0x00];
362 assert!(matches!(
363 FrameHeader::decode(&buf),
364 Err(WireError::UnknownFrameType(0x0F))
365 ));
366 }
367
368 #[test]
369 fn display_format() {
370 let h = FrameHeader::data(5, 42).with_encrypted();
371 let s = format!("{h}");
372 assert!(s.contains("DATA"));
373 assert!(s.contains("ch=5"));
374 assert!(s.contains("len=42"));
375 assert!(s.contains("E")); }
377
378 #[test]
379 fn all_frame_types_encode_decode() {
380 let types = [
381 FrameType::Data,
382 FrameType::HandshakeInit,
383 FrameType::HandshakeReply,
384 FrameType::HandshakeComplete,
385 FrameType::Ping,
386 FrameType::Pong,
387 FrameType::Close,
388 FrameType::FileHeader,
389 FrameType::FileChunk,
390 FrameType::Ack,
391 ];
392 for ft in types {
393 let h = FrameHeader {
394 frame_type: ft,
395 flags: FrameFlags::default(),
396 channel_id: 0,
397 stream_id: 0,
398 payload_len: 0,
399 };
400 let mut buf = [0u8; 32];
401 let n = h.encode(&mut buf).unwrap();
402 let (decoded, _) = FrameHeader::decode(&buf[..n]).unwrap();
403 assert_eq!(decoded.frame_type, ft, "type {ft} failed roundtrip");
404 }
405 }
406}