use crate::tag::ValueType;
use std::fmt::{Debug, Formatter};
pub struct Reader<'a> {
buffer: &'a [u8],
cursor: usize,
}
impl<'a> Reader<'a> {
pub fn new(buffer: &[u8]) -> Reader {
Reader { buffer, cursor: 0 }
}
pub fn take(&mut self, count: usize) -> CodecResult<&[u8]> {
if self.remaining() < count {
return Err(CodecError::NotEnoughBytes(
self.cursor,
count,
self.remaining(),
));
}
let current = self.cursor;
self.cursor += count;
Ok(&self.buffer[current..current + count])
}
pub fn take_one(&mut self) -> CodecResult<u8> {
if self.remaining() < 1 {
return Err(CodecError::NotEnoughBytes(self.cursor, 1, 0));
}
let byte = self.buffer[self.cursor];
self.cursor += 1;
Ok(byte)
}
pub fn step_back(&mut self) {
self.cursor -= 1;
}
pub fn remaining(&self) -> usize {
self.buffer.len() - self.cursor
}
}
pub enum CodecError {
MissingField(&'static str),
DecodeFail(&'static str, Box<CodecError>),
UnexpectedType(ValueType, ValueType),
UnexpectedFieldType(&'static str, ValueType, ValueType),
NotEnoughBytes(usize, usize, usize),
UnknownError,
DecodedTwice,
}
impl Debug for CodecError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
CodecError::MissingField(field) => write!(f, "Missing field {field}"),
CodecError::DecodeFail(field, err) => {
write!(f, "Unable to decode field {}: {:?}", field, err)
}
CodecError::UnexpectedType(expected, got) => {
write!(
f,
"Unexpected type; expected {:?} but got {:?}",
expected, got
)
}
CodecError::UnexpectedFieldType(field, expected, got) => {
write!(
f,
"Unexpected type for field {} expected {:?} but got {:?}",
field, expected, got
)
}
CodecError::NotEnoughBytes(cursor, wanted, remaining) => {
write!(
f,
"Didn't have enough bytes (cursor: {}, wanted: {}, remaining: {})",
cursor, wanted, remaining
)
}
CodecError::UnknownError => {
f.write_str("Unknown error occurred when trying to fit bytes")
}
CodecError::DecodedTwice => f.write_str("Attempted to decode packet contents twice"),
}
}
}
pub type CodecResult<T> = Result<T, CodecError>;
pub trait Codec: Sized {
fn encode(&self, output: &mut Vec<u8>);
fn decode(reader: &mut Reader) -> CodecResult<Self>;
fn skip(reader: &mut Reader) -> CodecResult<()> {
Self::decode(reader)?;
Ok(())
}
#[inline]
fn value_type() -> ValueType {
ValueType::Unknown(0)
}
fn encode_bytes(&self) -> Vec<u8> {
let mut output = Vec::new();
self.encode(&mut output);
output
}
}
pub fn decode_u16(value: &[u8]) -> CodecResult<u16> {
Ok(u16::from_be_bytes(
value.try_into().map_err(|_| CodecError::UnknownError)?,
))
}
pub fn encode_u16(value: &u16, output: &mut Vec<u8>) {
let bytes = value.to_be_bytes();
output.extend_from_slice(&bytes);
}
#[cfg(test)]
mod test {
use crate::codec::Reader;
#[test]
pub fn test_reader_take_one() {
let bytes = [0, 15, 23, 5, 10, 0];
let mut reader = Reader::new(&bytes);
for i in 0..bytes.len() {
let byte = bytes[i];
let got = reader.take_one().unwrap();
assert_eq!(byte, got)
}
}
}