use crate::error::Error;
use bytes::{Buf, BufMut, Bytes, BytesMut};
pub trait FixedSize {
const SIZE: usize;
}
pub trait EncodeSize {
fn encode_size(&self) -> usize;
fn encode_inline_size(&self) -> usize {
self.encode_size()
}
}
impl<T: FixedSize> EncodeSize for T {
fn encode_size(&self) -> usize {
Self::SIZE
}
}
pub trait Write {
fn write(&self, buf: &mut impl BufMut);
fn write_bufs(&self, buf: &mut impl BufsMut) {
self.write(buf);
}
}
pub trait Read: Sized {
type Cfg: Clone + Send + Sync + 'static;
fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error>;
}
pub trait Encode: Write + EncodeSize {
fn encode(&self) -> Bytes {
self.encode_mut().freeze()
}
fn encode_mut(&self) -> BytesMut {
let len = self.encode_size();
let mut buffer = BytesMut::with_capacity(len);
self.write(&mut buffer);
assert_eq!(buffer.len(), len, "write() did not write expected bytes");
buffer
}
}
impl<T: Write + EncodeSize> Encode for T {}
pub trait EncodeShared: Encode + Send + Sync {}
impl<T: Encode + Send + Sync> EncodeShared for T {}
pub trait Decode: Read {
fn decode_cfg(mut buf: impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
let result = Self::read_cfg(&mut buf, cfg)?;
let remaining = buf.remaining();
if remaining > 0 {
return Err(Error::ExtraData(remaining));
}
Ok(result)
}
}
impl<T: Read> Decode for T {}
pub trait Codec: Encode + Decode {}
impl<T: Encode + Decode> Codec for T {}
pub trait EncodeFixed: Write + FixedSize {
fn encode_fixed<const N: usize>(&self) -> [u8; N] {
assert_eq!(
N,
Self::SIZE,
"Can't encode {} bytes into {} bytes",
Self::SIZE,
N
);
let mut array = [0u8; N];
let mut buf = &mut array[..];
self.write(&mut buf);
assert_eq!(buf.len(), 0);
array
}
}
impl<T: Write + FixedSize> EncodeFixed for T {}
pub trait CodecFixed: Codec + FixedSize {}
impl<T: Codec + FixedSize> CodecFixed for T {}
pub trait CodecShared: Codec + Send + Sync {}
impl<T: Codec + Send + Sync> CodecShared for T {}
pub trait CodecFixedShared: CodecFixed<Cfg = ()> + Send + Sync {}
impl<T: CodecFixed<Cfg = ()> + Send + Sync> CodecFixedShared for T {}
pub trait BufsMut: BufMut {
fn push(&mut self, bytes: impl Into<Bytes>);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
extensions::{DecodeExt, ReadExt},
Error,
};
use bytes::Bytes;
#[test]
fn test_insufficient_buffer() {
let mut reader = Bytes::from_static(&[0x01, 0x02]);
assert!(matches!(u32::read(&mut reader), Err(Error::EndOfBuffer)));
}
#[test]
fn test_extra_data() {
let encoded = Bytes::from_static(&[0x01, 0x02]);
assert!(matches!(u8::decode(encoded), Err(Error::ExtraData(1))));
}
#[test]
fn test_encode_fixed() {
let value = 42u32;
let encoded: [u8; 4] = value.encode_fixed();
let decoded = <u32>::decode(&encoded[..]).unwrap();
assert_eq!(value, decoded);
}
#[test]
#[should_panic(expected = "Can't encode 4 bytes into 5 bytes")]
fn test_encode_fixed_panic() {
let _: [u8; 5] = 42u32.encode_fixed();
}
}