sansio_codec/byte_to_message_decoder/
line_based_frame_decoder.rs1use super::MessageDecoder;
2
3use bytes::BytesMut;
4
5#[derive(Default, PartialEq, Eq)]
7pub enum TerminatorType {
8 #[default]
10 BOTH,
11
12 NEWLINE,
14
15 CarriageNewline,
17}
18
19#[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 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}