use std::io::Cursor; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use anyhow::Result; use uuid::Uuid; pub mod clientbound; pub mod serverbound; pub trait Decode: Sized { fn decode(cursor: &mut Cursor<&[u8]>) -> Result; } pub trait Encode: Sized { fn encode(&self, buffer: &mut Vec) -> Result<()>; } pub trait Packet: Decode + Encode { fn get_id(&self) -> i32; } impl Encode for Option where T: Encode { fn encode(&self, buffer: &mut Vec) -> Result<()> { match self { Some(it) => it.encode(buffer), None => Ok(()) } } } macro_rules! number_impl { ($($type:ty, $read_fn:tt, $write_fn:tt),* $(,)?) => { $( impl Decode for $type { fn decode(cursor: &mut Cursor<&[u8]>) -> Result { cursor.$read_fn::().map_err(anyhow::Error::from) } } impl Encode for $type { fn encode(&self, buffer: &mut Vec) -> Result<()> { buffer.$write_fn::(*self).map_err(anyhow::Error::from) } } )* } } number_impl! { u16, read_u16, write_u16, u32, read_u32, write_u32, u64, read_u64, write_u64, i16, read_i16, write_i16, i32, read_i32, write_i32, i64, read_i64, write_i64, f32, read_f32, write_f32, f64, read_f64, write_f64, } impl Decode for bool { fn decode(cursor: &mut Cursor<&[u8]>) -> Result { let data = cursor.read_u8()?; Ok(data != 0x00) } } impl Encode for bool { fn encode(&self, buffer: &mut Vec) -> Result<()> { if *self { buffer.push(0x01); } else { buffer.push(0x00); } Ok(()) } } impl Decode for Uuid { fn decode(cursor: &mut Cursor<&[u8]>) -> Result { let data = cursor.read_u128::()?; Ok(Uuid::from_u128(data)) } } impl Encode for Uuid { fn encode(&self, buffer: &mut Vec) -> Result<()> { buffer.write_u128::(self.as_u128())?; Ok(()) } }