use std::fmt;
#[derive(Clone, Debug)]
pub struct DecodeError(pub &'static str);
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "payload decode error: {}", self.0)
}
}
impl std::error::Error for DecodeError {}
pub trait Payload: Clone + Send + Sync + 'static {
fn encode(&self, buf: &mut Vec<u8>);
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError>;
fn fixed_stride() -> Option<usize> { None }
}
impl Payload for () {
fn encode(&self, _buf: &mut Vec<u8>) {}
fn decode(_data: &[u8]) -> Result<(Self, usize), DecodeError> { Ok(((), 0)) }
fn fixed_stride() -> Option<usize> { Some(0) }
}
impl Payload for f32 {
fn encode(&self, buf: &mut Vec<u8>) { buf.extend_from_slice(&self.to_le_bytes()); }
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError> {
if data.len() < 4 { return Err(DecodeError("f32: too short")); }
Ok((f32::from_le_bytes(data[..4].try_into().unwrap()), 4))
}
fn fixed_stride() -> Option<usize> { Some(4) }
}
impl Payload for f64 {
fn encode(&self, buf: &mut Vec<u8>) { buf.extend_from_slice(&self.to_le_bytes()); }
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError> {
if data.len() < 8 { return Err(DecodeError("f64: too short")); }
Ok((f64::from_le_bytes(data[..8].try_into().unwrap()), 8))
}
fn fixed_stride() -> Option<usize> { Some(8) }
}
impl Payload for u32 {
fn encode(&self, buf: &mut Vec<u8>) { buf.extend_from_slice(&self.to_le_bytes()); }
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError> {
if data.len() < 4 { return Err(DecodeError("u32: too short")); }
Ok((u32::from_le_bytes(data[..4].try_into().unwrap()), 4))
}
fn fixed_stride() -> Option<usize> { Some(4) }
}
impl Payload for i32 {
fn encode(&self, buf: &mut Vec<u8>) { buf.extend_from_slice(&self.to_le_bytes()); }
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError> {
if data.len() < 4 { return Err(DecodeError("i32: too short")); }
Ok((i32::from_le_bytes(data[..4].try_into().unwrap()), 4))
}
fn fixed_stride() -> Option<usize> { Some(4) }
}
impl Payload for u64 {
fn encode(&self, buf: &mut Vec<u8>) { buf.extend_from_slice(&self.to_le_bytes()); }
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError> {
if data.len() < 8 { return Err(DecodeError("u64: too short")); }
Ok((u64::from_le_bytes(data[..8].try_into().unwrap()), 8))
}
fn fixed_stride() -> Option<usize> { Some(8) }
}
impl Payload for i64 {
fn encode(&self, buf: &mut Vec<u8>) { buf.extend_from_slice(&self.to_le_bytes()); }
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError> {
if data.len() < 8 { return Err(DecodeError("i64: too short")); }
Ok((i64::from_le_bytes(data[..8].try_into().unwrap()), 8))
}
fn fixed_stride() -> Option<usize> { Some(8) }
}
impl Payload for String {
fn encode(&self, buf: &mut Vec<u8>) {
let bytes = self.as_bytes();
buf.extend_from_slice(&(bytes.len() as u32).to_le_bytes());
buf.extend_from_slice(bytes);
}
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError> {
if data.len() < 4 { return Err(DecodeError("String: too short for length")); }
let len = u32::from_le_bytes(data[..4].try_into().unwrap()) as usize;
if data.len() < 4 + len { return Err(DecodeError("String: truncated data")); }
let s = std::str::from_utf8(&data[4..4 + len])
.map_err(|_| DecodeError("String: invalid UTF-8"))?
.to_owned();
Ok((s, 4 + len))
}
}
impl Payload for Vec<u8> {
fn encode(&self, buf: &mut Vec<u8>) {
buf.extend_from_slice(&(self.len() as u32).to_le_bytes());
buf.extend_from_slice(self);
}
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError> {
if data.len() < 4 { return Err(DecodeError("Vec<u8>: too short for length")); }
let len = u32::from_le_bytes(data[..4].try_into().unwrap()) as usize;
if data.len() < 4 + len { return Err(DecodeError("Vec<u8>: truncated data")); }
Ok((data[4..4 + len].to_vec(), 4 + len))
}
}
impl Payload for Vec<f32> {
fn encode(&self, buf: &mut Vec<u8>) {
buf.extend_from_slice(&(self.len() as u32).to_le_bytes());
for &v in self {
buf.extend_from_slice(&v.to_le_bytes());
}
}
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError> {
if data.len() < 4 { return Err(DecodeError("Vec<f32>: too short for count")); }
let count = u32::from_le_bytes(data[..4].try_into().unwrap()) as usize;
let needed = 4 + count * 4;
if data.len() < needed { return Err(DecodeError("Vec<f32>: truncated data")); }
let floats = data[4..needed]
.chunks_exact(4)
.map(|c| f32::from_le_bytes(c.try_into().unwrap()))
.collect();
Ok((floats, needed))
}
}
impl<A: Payload, B: Payload> Payload for (A, B) {
fn encode(&self, buf: &mut Vec<u8>) {
self.0.encode(buf);
self.1.encode(buf);
}
fn decode(data: &[u8]) -> Result<(Self, usize), DecodeError> {
let (a, na) = A::decode(data)?;
let (b, nb) = B::decode(&data[na..])?;
Ok(((a, b), na + nb))
}
fn fixed_stride() -> Option<usize> {
match (A::fixed_stride(), B::fixed_stride()) {
(Some(a), Some(b)) => Some(a + b),
_ => None,
}
}
}