compio_io/framed/
frame.rs1use std::io;
4
5use compio_buf::{
6 IoBuf, IoBufMut, Slice,
7 bytes::{Buf, BufMut},
8};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct Frame {
13 prefix: usize,
15
16 payload: usize,
18
19 suffix: usize,
21}
22
23impl Frame {
24 pub fn new(prefix: usize, payload: usize, suffix: usize) -> Self {
27 Self {
28 prefix,
29 payload,
30 suffix,
31 }
32 }
33
34 pub fn len(&self) -> usize {
36 self.prefix + self.payload + self.suffix
37 }
38
39 pub fn is_empty(&self) -> bool {
41 self.len() == 0
42 }
43
44 pub fn slice<B: IoBuf>(&self, buf: B) -> Slice<B> {
46 buf.slice(self.prefix..self.prefix + self.payload)
47 }
48}
49
50pub trait Framer<B: IoBufMut> {
52 fn enclose(&mut self, buf: &mut B);
61
62 fn extract(&mut self, buf: &Slice<B>) -> io::Result<Option<Frame>>;
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
75pub struct LengthDelimited {
76 length_field_len: usize,
77 length_field_is_big_endian: bool,
78}
79
80impl Default for LengthDelimited {
81 fn default() -> Self {
82 Self {
83 length_field_len: 4,
84 length_field_is_big_endian: true,
85 }
86 }
87}
88
89impl LengthDelimited {
90 pub fn new() -> Self {
92 Self::default()
93 }
94
95 pub fn length_field_len(&self) -> usize {
97 self.length_field_len
98 }
99
100 pub fn set_length_field_len(mut self, len_field_len: usize) -> Self {
102 self.length_field_len = len_field_len;
103 self
104 }
105
106 pub fn length_field_is_big_endian(&self) -> bool {
108 self.length_field_is_big_endian
109 }
110
111 pub fn set_length_field_is_big_endian(mut self, big_endian: bool) -> Self {
113 self.length_field_is_big_endian = big_endian;
114 self
115 }
116}
117
118impl<B: IoBufMut> Framer<B> for LengthDelimited {
119 fn enclose(&mut self, buf: &mut B) {
120 let len = (*buf).buf_len();
121
122 buf.reserve(self.length_field_len).expect("Reserve failed");
123 buf.copy_within(0..len, self.length_field_len); unsafe { buf.advance_to(len + self.length_field_len) };
125
126 let slice = buf.as_mut_slice();
127
128 if self.length_field_is_big_endian {
130 (&mut slice[0..self.length_field_len]).put_uint(len as _, self.length_field_len);
131 } else {
132 (&mut slice[0..self.length_field_len]).put_uint_le(len as _, self.length_field_len);
133 }
134 }
135
136 fn extract(&mut self, buf: &Slice<B>) -> io::Result<Option<Frame>> {
137 if buf.len() < self.length_field_len {
138 return Ok(None);
139 }
140
141 let mut buf = buf.as_init();
142
143 let len = if self.length_field_is_big_endian {
144 buf.get_uint(self.length_field_len)
145 } else {
146 buf.get_uint_le(self.length_field_len)
147 } as usize;
148
149 if buf.len() < len {
150 return Ok(None);
151 }
152
153 Ok(Some(Frame::new(self.length_field_len, len, 0)))
154 }
155}
156
157#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
162pub struct CharDelimited<const C: char> {
163 char_buf: [u8; 4],
164}
165
166impl<const C: char> CharDelimited<C> {
167 pub fn new() -> Self {
169 Self { char_buf: [0; 4] }
170 }
171
172 fn as_any_delimited(&mut self) -> AnyDelimited<'_> {
173 let bytes = C.encode_utf8(&mut self.char_buf).as_bytes();
174
175 AnyDelimited::new(bytes)
176 }
177}
178
179impl<B: IoBufMut, const C: char> Framer<B> for CharDelimited<C> {
180 fn enclose(&mut self, buf: &mut B) {
181 self.as_any_delimited().enclose(buf);
182 }
183
184 fn extract(&mut self, buf: &Slice<B>) -> io::Result<Option<Frame>> {
185 self.as_any_delimited().extract(buf)
186 }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
191pub struct AnyDelimited<'a> {
192 bytes: &'a [u8],
193}
194
195impl<'a> AnyDelimited<'a> {
196 pub fn new(bytes: &'a [u8]) -> Self {
198 Self { bytes }
199 }
200}
201
202impl<B: IoBufMut> Framer<B> for AnyDelimited<'_> {
203 fn extract(&mut self, buf: &Slice<B>) -> io::Result<Option<Frame>> {
204 if buf.is_empty() {
205 return Ok(None);
206 }
207
208 if let Some(pos) = buf
211 .windows(self.bytes.len())
212 .position(|window| window == self.bytes)
213 {
214 Ok(Some(Frame::new(0, pos, self.bytes.len())))
215 } else {
216 Ok(None)
217 }
218 }
219
220 fn enclose(&mut self, buf: &mut B) {
221 buf.extend_from_slice(self.bytes)
222 .expect("Failed to append delimiter");
223 }
224}
225
226pub type LineDelimited = CharDelimited<'\n'>;
228
229#[cfg(test)]
230mod tests {
231 use compio_buf::{IntoInner, IoBufMut};
232
233 use super::*;
234
235 #[test]
236 fn test_length_delimited() {
237 let mut framer = LengthDelimited::new();
238
239 let mut buf = Vec::from(b"hello");
240 framer.enclose(&mut buf);
241 assert_eq!(&buf.as_slice()[..9], b"\x00\x00\x00\x05hello");
242
243 let buf = buf.slice(..);
244 let frame = framer.extract(&buf).unwrap().unwrap();
245 let buf = buf.into_inner();
246 assert_eq!(frame, Frame::new(4, 5, 0));
247 let payload = frame.slice(buf);
248 assert_eq!(payload.as_init(), b"hello");
249 }
250
251 #[test]
252 fn test_char_delimited() {
253 let mut framer = CharDelimited::<'ℝ'>::new();
254
255 let mut buf = Vec::new();
256 IoBufMut::extend_from_slice(&mut buf, b"hello").unwrap();
257 framer.enclose(&mut buf);
258 assert_eq!(buf.as_slice(), "helloℝ".as_init());
259
260 let buf = buf.slice(..);
261 let frame = framer.extract(&buf).unwrap().unwrap();
262 assert_eq!(frame, Frame::new(0, 5, 3));
263 let payload = frame.slice(buf);
264 assert_eq!(payload.as_init(), b"hello");
265 }
266}