Skip to main content

lhm_shared/
codec.rs

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        // Ensure we have the full required header bytes
19        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        // Not enough bytes for the whole message
61        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}