retty/codec/byte_to_message_decoder/
line_based_frame_decoder.rs1use crate::codec::byte_to_message_decoder::MessageDecoder;
2
3use bytes::BytesMut;
4use std::io::ErrorKind;
5
6#[derive(Default, PartialEq, Eq)]
8pub enum TerminatorType {
9 #[default]
11 BOTH,
12
13 NEWLINE,
15
16 CarriageNewline,
18}
19
20#[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 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}