use std::io;
use bytes::BytesMut;
use tokio_util::codec::{Decoder, Encoder, LengthDelimitedCodec};
pub struct Codec {
inner: LengthDelimitedCodec,
frame_size: usize,
}
impl Codec {
pub fn new(frame_size: usize, max_frame_size: usize) -> Self {
assert!(frame_size > 0, "frame_size must be non-zero");
let inner = LengthDelimitedCodec::builder()
.max_frame_length(max_frame_size)
.length_field_length(4)
.big_endian()
.new_codec();
Self { inner, frame_size }
}
pub fn frame_size(&self) -> usize {
self.frame_size
}
}
impl Decoder for Codec {
type Item = BytesMut;
type Error = io::Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
match self.inner.decode(src)? {
Some(buf) => {
if buf.len() != self.frame_size {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"unexpected frame size: got {}, want {}",
buf.len(),
self.frame_size
),
));
}
Ok(Some(buf))
}
None => Ok(None),
}
}
}
impl Encoder<BytesMut> for Codec {
type Error = io::Error;
fn encode(&mut self, item: BytesMut, dst: &mut BytesMut) -> Result<(), Self::Error> {
if item.len() != self.frame_size {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"unexpected frame size: got {}, want {}",
item.len(),
self.frame_size
),
));
}
self.inner.encode(item.freeze(), dst)
}
}