retty/codec/byte_to_message_decoder/
line_based_frame_decoder.rs

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