1use tokio_util::{
2 bytes::{Buf, BufMut, Bytes, BytesMut},
3 codec::{Decoder, Encoder},
4};
5
6pub struct LHMFrame {
7 pub id: u32,
8 pub body: Bytes,
9}
10
11pub struct LHMFrameHeader {
12 length: u32,
13 id: u32,
14}
15
16impl LHMFrameHeader {
17 pub fn try_decode(src: &mut BytesMut) -> Option<LHMFrameHeader> {
18 if src.len() < 8 {
20 return None;
21 }
22
23 let id = src.get_u32();
24 let length = src.get_u32();
25 Some(LHMFrameHeader { length, id })
26 }
27}
28
29#[derive(Default)]
30pub struct LHMFrameCodec {
31 header: Option<LHMFrameHeader>,
32}
33
34impl Encoder<LHMFrame> for LHMFrameCodec {
35 type Error = std::io::Error;
36
37 fn encode(&mut self, item: LHMFrame, dst: &mut BytesMut) -> Result<(), Self::Error> {
38 dst.put_u32(item.id);
39 dst.put_u32(item.body.len() as u32);
40 dst.extend_from_slice(&item.body);
41 Ok(())
42 }
43}
44
45impl Decoder for LHMFrameCodec {
46 type Item = LHMFrame;
47 type Error = std::io::Error;
48
49 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
50 let header = match self.header.as_mut() {
51 Some(value) => value,
52 None => match LHMFrameHeader::try_decode(src) {
53 Some(value) => self.header.insert(value),
54 None => return Ok(None),
55 },
56 };
57
58 let length = header.length as usize;
59
60 if src.len() < length {
62 return Ok(None);
63 }
64
65 let header = self
66 .header
67 .take()
68 .expect("impossible to read a frame without a header");
69
70 let bytes = src.split_to(length);
71
72 Ok(Some(LHMFrame {
73 id: header.id,
74 body: bytes.freeze(),
75 }))
76 }
77}