use crate::WireError;
use bytes::{Bytes, BytesMut};
pub trait WireEncode {
fn encode(&self, buf: &mut BytesMut);
fn encoded_size(&self) -> usize;
#[must_use]
fn to_bytes(&self) -> Bytes {
let mut buf = BytesMut::with_capacity(self.encoded_size());
self.encode(&mut buf);
buf.freeze()
}
}
pub trait WireDecode: Sized {
fn decode(buf: &[u8]) -> Result<(Self, usize), WireError>;
fn decode_from(buf: &[u8]) -> Result<Self, WireError> {
Self::decode(buf).map(|(val, _)| val)
}
}
#[inline]
pub fn read_u8(buf: &[u8], offset: usize) -> Result<u8, WireError> {
buf.get(offset)
.copied()
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: 1,
have: buf.len().saturating_sub(offset),
})
}
#[allow(clippy::missing_panics_doc)]
#[inline]
pub fn read_u32_le(buf: &[u8], offset: usize) -> Result<u32, WireError> {
let end = offset
.checked_add(4)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: 4,
have: buf.len().saturating_sub(offset),
})?;
let slice = buf
.get(offset..end)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: 4,
have: buf.len().saturating_sub(offset),
})?;
Ok(u32::from_le_bytes(
slice.try_into().expect("slice is exactly 4 bytes"),
))
}
#[allow(clippy::missing_panics_doc)]
#[inline]
pub fn read_u64_le(buf: &[u8], offset: usize) -> Result<u64, WireError> {
let end = offset
.checked_add(8)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: 8,
have: buf.len().saturating_sub(offset),
})?;
let slice = buf
.get(offset..end)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: 8,
have: buf.len().saturating_sub(offset),
})?;
Ok(u64::from_le_bytes(
slice.try_into().expect("slice is exactly 8 bytes"),
))
}
#[inline]
pub fn read_str(buf: &[u8], offset: usize, len: usize) -> Result<String, WireError> {
let end = offset
.checked_add(len)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: len,
have: buf.len().saturating_sub(offset),
})?;
let slice = buf
.get(offset..end)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: len,
have: buf.len().saturating_sub(offset),
})?;
std::str::from_utf8(slice)
.map(str::to_string)
.map_err(|_| WireError::InvalidUtf8 { offset })
}
#[allow(clippy::missing_panics_doc)]
#[inline]
pub fn read_u128_le(buf: &[u8], offset: usize) -> Result<u128, WireError> {
let end = offset
.checked_add(16)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: 16,
have: buf.len().saturating_sub(offset),
})?;
let slice = buf
.get(offset..end)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: 16,
have: buf.len().saturating_sub(offset),
})?;
Ok(u128::from_le_bytes(
slice.try_into().expect("slice is exactly 16 bytes"),
))
}
#[allow(clippy::missing_panics_doc)]
#[inline]
pub fn read_f32_le(buf: &[u8], offset: usize) -> Result<f32, WireError> {
let end = offset
.checked_add(4)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: 4,
have: buf.len().saturating_sub(offset),
})?;
let slice = buf
.get(offset..end)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: 4,
have: buf.len().saturating_sub(offset),
})?;
Ok(f32::from_le_bytes(
slice.try_into().expect("slice is exactly 4 bytes"),
))
}
#[inline]
pub fn read_bytes(buf: &[u8], offset: usize, len: usize) -> Result<&[u8], WireError> {
let end = offset
.checked_add(len)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: len,
have: buf.len().saturating_sub(offset),
})?;
buf.get(offset..end)
.ok_or_else(|| WireError::UnexpectedEof {
offset,
need: len,
have: buf.len().saturating_sub(offset),
})
}