use crate::builder::*;
use crate::error::*;
pub use crate::packet::{ConnectComm, CoptFrame, DtData, Parameter, PduType, TpduSize};
use bytes::{Buf, BufMut, BytesMut};
use std::fmt::Debug;
use tokio_util::codec::{Decoder, Encoder};
pub mod builder;
pub mod error;
mod packet;
#[derive(Default)]
pub struct CoptEncoder<E>(pub E);
pub struct CoptDecoder<D>(pub D);
impl<F: Debug + Eq + PartialEq, E: Encoder<F>> Encoder<CoptFrame<F>> for CoptEncoder<E>
where
<E as Encoder<F>>::Error: ToCoptError + Send + Sync + 'static,
{
type Error = Error;
fn encode(
&mut self,
item: CoptFrame<F>,
dst: &mut BytesMut,
) -> std::result::Result<(), Self::Error> {
dst.put_u8(item.length());
match item.pdu_type {
PduType::ConnectRequest(conn) => {
dst.put_u8(0xe0);
conn.encode(dst);
Ok(())
}
PduType::ConnectConfirm(conn) => {
dst.put_u8(0xd0);
conn.encode(dst);
Ok(())
}
PduType::DtData(conn) => {
dst.put_u8(0xf0);
let merge =
conn.tpdu_number >> 1 | if conn.last_data_unit { 0b1000_0000 } else { 0 };
dst.put_u8(merge);
Ok(self.0.encode(conn.payload, dst)?)
}
}
}
}
impl<F: Debug + Eq + PartialEq, D: Decoder<Item = F>> Decoder for CoptDecoder<D>
where
<D as Decoder>::Error: ToCoptError + Send + Sync + 'static,
{
type Item = CoptFrame<F>;
type Error = Error;
fn decode(
&mut self,
src: &mut BytesMut,
) -> std::result::Result<Option<Self::Item>, Self::Error> {
let (Some(length), Some(pdu_type)) = (src.get(0), src.get(1)) else {
return Ok(None)
};
let length = *length as usize + 1;
if src.len() < length || length < 2 {
return Ok(None);
};
match *pdu_type {
0xe0 => {
let mut src = src.split_to(length).split_off(2);
Ok(Some(CoptFrame {
pdu_type: PduType::ConnectRequest(ConnectComm::decode(&mut src)?),
}))
}
0xd0 => {
let mut src = src.split_to(length).split_off(2);
Ok(Some(CoptFrame {
pdu_type: PduType::ConnectConfirm(ConnectComm::decode(&mut src)?),
}))
}
0xf0 => {
let mut sub_src = src.clone().split_off(length);
let pre_length = sub_src.len();
let Some(f) = self.0.decode(&mut sub_src)? else {
return Err(Error::Error("decode fail".to_string()));
};
let sub_length = pre_length - sub_src.len();
let mut src = src.split_to(length + sub_length).split_off(2);
let merge = src.get_u8();
let tpdu_number = merge & 0b0111_1111;
let last_data_unit = merge & 0b1000_0000 > 0;
Ok(Some(CoptFrame {
pdu_type: PduType::DtData(DtData {
tpdu_number,
last_data_unit,
payload: f,
}),
}))
}
_ => {
return Err(Error::Error(format!("not support pdu type: {}", pdu_type)));
}
}
}
}