use bytes::{Buf, BufMut, BytesMut};
use std::convert::TryInto;
use tokio::io;
use tokio_util::codec::{Decoder, Encoder};
static LEN_SIZE: usize = 8;
#[inline]
fn frame_size(msg_size: usize) -> usize {
LEN_SIZE + msg_size
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct DistantCodec;
impl<'a> Encoder<&'a [u8]> for DistantCodec {
type Error = io::Error;
fn encode(&mut self, item: &'a [u8], dst: &mut BytesMut) -> Result<(), Self::Error> {
dst.reserve(frame_size(item.len()));
dst.put_u64(item.len() as u64);
dst.put(item);
Ok(())
}
}
impl Decoder for DistantCodec {
type Item = Vec<u8>;
type Error = io::Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if src.len() <= LEN_SIZE {
return Ok(None);
}
let msg_len = u64::from_be_bytes(src[..LEN_SIZE].try_into().unwrap());
let frame_len = frame_size(msg_len as usize);
if src.len() >= frame_len {
let data = src[LEN_SIZE..frame_len].to_vec();
src.advance(frame_len);
Ok(Some(data))
} else {
Ok(None)
}
}
}