use crate::{
error::{DecodeError, DecodeErrorKind},
message::{decode, Message},
sink::Sink,
wire::{self, Wire},
};
use bytes::Bytes;
pub trait Body: Clone + Sized + 'static {
fn body_len(&self) -> usize;
fn put_body<S: Sink>(&self, out: &mut S);
fn from_body(bytes: Bytes) -> Result<Self, DecodeError>;
}
impl<T: Message + Clone + 'static> Body for T {
#[inline]
fn body_len(&self) -> usize {
self.encoded_len()
}
#[inline]
fn put_body<S: Sink>(&self, out: &mut S) {
self.encode(out);
}
#[inline]
fn from_body(bytes: Bytes) -> Result<Self, DecodeError> {
T::decode(bytes)
}
}
impl<T: Body> Body for Option<T> {
fn body_len(&self) -> usize {
match self {
Some(inner) => 1 + inner.body_len(),
None => 1,
}
}
fn put_body<S: Sink>(&self, out: &mut S) {
match self {
Some(inner) => {
out.put_u8(1);
inner.put_body(out);
}
None => out.put_u8(0),
}
}
fn from_body(mut bytes: Bytes) -> Result<Self, DecodeError> {
let Some(&tag) = bytes.first() else {
return Err(DecodeError::new(DecodeErrorKind::Truncated, 0));
};
match tag {
0 if bytes.len() == 1 => Ok(None),
0 => Err(DecodeError::new(DecodeErrorKind::TrailingBytes, 1)),
1 => T::from_body(bytes.split_off(1)).map(Some),
_ => Err(DecodeError::new(DecodeErrorKind::InvalidTag, 0)),
}
}
}
macro_rules! wire_body {
($($ty:ty => $marker:ty),* $(,)?) => {
$(
impl Body for $ty {
#[inline]
fn body_len(&self) -> usize {
<$marker as Wire>::encoded_len(self)
}
#[inline]
fn put_body<S: Sink>(&self, out: &mut S) {
<$marker as Wire>::encode(self, out);
}
#[inline]
fn from_body(bytes: Bytes) -> Result<Self, DecodeError> {
decode::<$marker>(&bytes)
}
}
)*
};
}
wire_body!(
bool => wire::Bool,
u8 => wire::U8,
u16 => wire::U16,
u32 => wire::U32,
u64 => wire::U64,
i8 => wire::I8,
i16 => wire::I16,
i32 => wire::I32,
i64 => wire::I64,
f32 => wire::F32,
f64 => wire::F64,
);