copt/
lib.rs

1use crate::builder::*;
2use crate::error::*;
3pub use crate::packet::{ConnectComm, CoptFrame, DtData, Parameter, PduType, TpduSize};
4use bytes::{Buf, BufMut, BytesMut};
5use std::fmt::Debug;
6use tokio_util::codec::{Decoder, Encoder};
7
8pub mod builder;
9pub mod error;
10mod packet;
11
12#[derive(Default)]
13pub struct CoptEncoder<E>(pub E);
14pub struct CoptDecoder<D>(pub D);
15
16impl<F: Debug + Eq + PartialEq, E: Encoder<F>> Encoder<CoptFrame<F>> for CoptEncoder<E>
17where
18    <E as Encoder<F>>::Error: ToCoptError + Send + Sync + 'static,
19{
20    type Error = Error;
21
22    fn encode(
23        &mut self,
24        item: CoptFrame<F>,
25        dst: &mut BytesMut,
26    ) -> std::result::Result<(), Self::Error> {
27        dst.put_u8(item.length());
28        match item.pdu_type {
29            PduType::ConnectRequest(conn) => {
30                dst.put_u8(0xe0);
31                conn.encode(dst);
32                Ok(())
33            }
34            PduType::ConnectConfirm(conn) => {
35                dst.put_u8(0xd0);
36                conn.encode(dst);
37                Ok(())
38            }
39            PduType::DtData(conn) => {
40                dst.put_u8(0xf0);
41                let merge =
42                    conn.tpdu_number >> 1 | if conn.last_data_unit { 0b1000_0000 } else { 0 };
43                dst.put_u8(merge);
44                Ok(self.0.encode(conn.payload, dst)?)
45            }
46        }
47    }
48}
49
50impl<F: Debug + Eq + PartialEq, D: Decoder<Item = F>> Decoder for CoptDecoder<D>
51where
52    <D as Decoder>::Error: ToCoptError + Send + Sync + 'static,
53{
54    type Item = CoptFrame<F>;
55    type Error = Error;
56
57    fn decode(
58        &mut self,
59        src: &mut BytesMut,
60    ) -> std::result::Result<Option<Self::Item>, Self::Error> {
61        let (Some(length), Some(pdu_type)) = (src.get(0), src.get(1)) else {
62            return Ok(None)
63        };
64        let length = *length as usize + 1;
65        if src.len() < length || length < 2 {
66            return Ok(None);
67        };
68        match *pdu_type {
69            // 0x0e?
70            0xe0 => {
71                let mut src = src.split_to(length).split_off(2);
72                Ok(Some(CoptFrame {
73                    pdu_type: PduType::ConnectRequest(ConnectComm::decode(&mut src)?),
74                }))
75            }
76            0xd0 => {
77                let mut src = src.split_to(length).split_off(2);
78                Ok(Some(CoptFrame {
79                    pdu_type: PduType::ConnectConfirm(ConnectComm::decode(&mut src)?),
80                }))
81            }
82            0xf0 => {
83                let mut sub_src = src.clone().split_off(length);
84                let pre_length = sub_src.len();
85                let Some(f) = self.0.decode(&mut sub_src)? else {
86                    return Err(Error::Error("decode fail".to_string()));
87
88                };
89                let sub_length = pre_length - sub_src.len();
90                let mut src = src.split_to(length + sub_length).split_off(2);
91                let merge = src.get_u8();
92                let tpdu_number = merge & 0b0111_1111;
93                let last_data_unit = merge & 0b1000_0000 > 0;
94                Ok(Some(CoptFrame {
95                    pdu_type: PduType::DtData(DtData {
96                        tpdu_number,
97                        last_data_unit,
98                        payload: f,
99                    }),
100                }))
101            }
102            _ => {
103                return Err(Error::Error(format!("not support pdu type: {}", pdu_type)));
104            }
105        }
106    }
107}