sansio_codec/byte_to_message_decoder/
line_based_frame_decoder.rs

1use super::MessageDecoder;
2
3use bytes::BytesMut;
4
5/// Delimiter with different terminator type \n` or `\r\n`
6#[derive(Default, PartialEq, Eq)]
7pub enum TerminatorType {
8    /// Delimiter with \n` or `\r\n`
9    #[default]
10    BOTH,
11
12    /// Delimiter with `\n` only
13    NEWLINE,
14
15    /// Delimiter with `\r\n` only
16    CarriageNewline,
17}
18
19/// A line based frame decoder with [TerminatorType] as delimiter
20#[derive(Default)]
21pub struct LineBasedFrameDecoder {
22    max_length: usize,
23    strip_delimiter: bool,
24    terminator_type: TerminatorType,
25
26    discarding: bool,
27    discarded_bytes: usize,
28}
29
30impl LineBasedFrameDecoder {
31    /// Creates a new LineBasedFrameDecoder
32    pub fn new(max_length: usize, strip_delimiter: bool, terminator_type: TerminatorType) -> Self {
33        Self {
34            max_length,
35            strip_delimiter,
36            terminator_type,
37            ..Default::default()
38        }
39    }
40
41    fn find_end_of_line(&mut self, buf: &BytesMut) -> Option<usize> {
42        let mut i = 0usize;
43        while i < self.max_length && i < buf.len() {
44            let b = buf[i];
45            if (b == b'\n' && self.terminator_type != TerminatorType::CarriageNewline)
46                || (self.terminator_type != TerminatorType::NEWLINE
47                    && b == b'\r'
48                    && i + 1 < buf.len()
49                    && buf[i + 1] == b'\n')
50            {
51                return Some(i);
52            }
53            i += 1;
54        }
55
56        None
57    }
58}
59
60impl MessageDecoder for LineBasedFrameDecoder {
61    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<BytesMut>, std::io::Error> {
62        let eol = self.find_end_of_line(buf);
63        let mut offset = 0;
64        if !self.discarding {
65            if let Some(eol) = eol {
66                offset += eol;
67                let delim_length = if buf[offset] == b'\r' { 2 } else { 1 };
68                if eol > self.max_length {
69                    return Err(std::io::Error::other(format!(
70                        "frame length {} exceeds max {}",
71                        eol, self.max_length
72                    )));
73                }
74
75                let frame = if self.strip_delimiter {
76                    let frame = buf.split_to(eol);
77                    let _ = buf.split_to(delim_length);
78                    frame
79                } else {
80                    buf.split_to(eol + delim_length)
81                };
82
83                Ok(Some(frame))
84            } else {
85                let len = buf.len();
86                if len > self.max_length {
87                    self.discarded_bytes = len;
88                    let _ = buf.split_to(len);
89                    self.discarding = true;
90                    Err(std::io::Error::other(format!("over {}", len)))
91                } else {
92                    Ok(None)
93                }
94            }
95        } else {
96            if let Some(eol) = eol {
97                offset += eol;
98                let delim_length = if buf[offset] == b'\r' { 2 } else { 1 };
99                let _ = buf.split_to(eol + delim_length);
100                self.discarded_bytes = 0;
101                self.discarding = false;
102            } else {
103                self.discarded_bytes = buf.len();
104                let _ = buf.split_to(buf.len());
105            }
106
107            Ok(None)
108        }
109    }
110}