1use std::io::IoSlice;
5
6use crate::stream_decoder::{Decoded, FrameCodec, StreamDecoder};
7
8#[derive(Debug, PartialEq, Eq, thiserror::Error)]
10#[error("frame exceeds the maximum size")]
11pub struct FrameTooLargeError;
12
13#[derive(Debug, PartialEq)]
14pub struct TcpFrame {
15 prefix: [u8; 2],
16 payload: Vec<u8>,
17}
18
19impl TcpFrame {
20 pub fn try_new(payload: Vec<u8>) -> Result<Self, FrameTooLargeError> {
27 let length = u16::try_from(payload.len()).map_err(|_e| FrameTooLargeError)?;
28 Ok(Self {
29 prefix: u16::to_be_bytes(length),
30 payload,
31 })
32 }
33
34 #[must_use]
36 pub fn is_null(&self) -> bool {
37 self.payload.is_empty()
38 }
39
40 #[must_use]
41 pub fn io_slices(&self) -> [IoSlice<'_>; 2] {
42 [IoSlice::new(&self.prefix), IoSlice::new(&self.payload)]
43 }
44 #[must_use]
45 pub fn into_payload(self) -> Vec<u8> {
46 self.payload
47 }
48
49 #[must_use]
50 pub fn payload(&self) -> &[u8] {
51 &self.payload
52 }
53}
54
55pub const MAX_FRAME_SIZE: u16 = 4096;
63
64pub type TcpFrameDecoder = StreamDecoder<TcpCodec>;
66
67#[derive(Debug)]
69pub struct TcpCodec;
70
71impl FrameCodec for TcpCodec {
72 type Frame = TcpFrame;
73 type Error = FrameTooLargeError;
74
75 fn try_decode(unread: &[u8]) -> Decoded<TcpFrame, FrameTooLargeError> {
76 let &[first, second] = unread.first_chunk::<2>()?;
77 let length = u16::from_be_bytes([first, second]);
78 if length > MAX_FRAME_SIZE {
79 return Some(Err(FrameTooLargeError));
80 }
81 let frame_end = 2 + usize::from(length);
82 let payload = unread.get(2..frame_end)?;
83 Some(TcpFrame::try_new(payload.to_vec()).map(|frame| (frame, frame_end)))
84 }
85}
86
87#[cfg(test)]
88#[path = "TESTS/tcp_framing.rs"]
89mod tests;