use crate::{Deserialize, DeserializeErr, Serialize}; use alloc::{string::String, fmt, vec::Vec}; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] pub struct ProtocolSpec { pub name: String, pub packets: Vec, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] pub struct ProtocolPacketSpec { pub state: String, pub direction: String, pub id: i32, pub name: String, pub body_struct: String, pub fields: Vec, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] pub struct ProtocolPacketField { pub name: String, pub kind: String, } pub trait PacketIdentifier: Clone + fmt::Debug + PartialEq + Serialize {} impl PacketIdentifier for T {} pub trait Packet: Serialize { fn id(&self) -> I; fn mc_deserialize(raw: RawPacket<'_, I>) -> Result; } pub enum PacketErr { UnknownId(i32), DeserializeFailed(DeserializeErr), ExtraData(Vec), } impl fmt::Display for PacketErr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use PacketErr::*; match self { UnknownId(id) => f.write_fmt(format_args!("unknown packet id {:?}", id)), DeserializeFailed(err) => { f.write_fmt(format_args!("failed to deserialize packet: {:?}", err)) } ExtraData(data) => f.write_fmt(format_args!( "extra data unparsed at end of packet: {:?}", data )), } } } impl fmt::Debug for PacketErr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ::fmt(self, f) } } #[cfg(feature = "std")] impl std::error::Error for PacketErr {} #[derive(Debug, Clone, PartialEq)] pub struct RawPacket<'a, I> { pub id: I, pub data: &'a [u8], } pub trait ProtocolType: Serialize + Deserialize {} impl ProtocolType for T {} #[cfg(all(test, feature = "std"))] pub trait TestRandom { fn test_gen_random() -> Self; } #[macro_export] macro_rules! as_item { ($i:item) => { $i }; } #[macro_export] macro_rules! __protocol_body_serialize_def_helper { ($to: ident, $slf: ident, $fieldn: ident, $($field_rest: ident),+) => { $to.serialize_other(&$slf.$fieldn)?; $crate::__protocol_body_serialize_def_helper!($to, $slf, $($field_rest),+); }; ( $to: ident, $slf: ident, $fieldn: ident ) => { $to.serialize_other(&$slf.$fieldn) }; } #[macro_export] macro_rules! __protocol_body_def_helper { ($bodyt: ident { }) => { #[derive(Debug, Clone, PartialEq, Default)] pub struct $bodyt; impl Serialize for $bodyt { fn mc_serialize(&self, _: &mut S) -> SerializeResult { Ok(()) } } impl Deserialize for $bodyt { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { Deserialized::ok(Self::default(), data) } } #[cfg(all(test, feature = "std"))] impl TestRandom for $bodyt { fn test_gen_random() -> Self { Self::default() } } }; ($bodyt: ident { $($fname: ident: $ftyp: ty ),+ }) => { $crate::as_item! { #[derive(Debug, Clone, PartialEq)] pub struct $bodyt { $(pub $fname: $ftyp),+ } } impl Serialize for $bodyt { fn mc_serialize(&self, to: &mut S) -> SerializeResult { $( to.serialize_other(&self.$fname)?; )+ Ok(()) } } impl Deserialize for $bodyt { fn mc_deserialize(_rest: &[u8]) -> DeserializeResult<'_, Self> { $(let Deserialized{ value: $fname, data: _rest } = <$ftyp>::mc_deserialize(_rest)?;)+ Deserialized::ok(Self{ $($fname),+ }, _rest) } } #[cfg(all(test, feature = "std"))] impl TestRandom for $bodyt { fn test_gen_random() -> Self { Self{ $($fname: <$ftyp>::test_gen_random()),+ } } } } } #[macro_export] macro_rules! define_protocol { ($packett: ident, $rawpackett: ident, $rawdt: ident, $directiont: ident, $statet: ident, $idt: ident, $idi: ident => { $($nam: ident, $id: literal, $state: ident, $direction: ident => $body: ident { $($fnam: ident: $ftyp: ty),* }),*}) => { #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct $idi { pub id: $idt, pub state: $statet, pub direction: $directiont } impl crate::Serialize for $idi { fn mc_serialize(&self, to: &mut S) -> SerializeResult { VarInt(self.id).mc_serialize(to) } } impl From<($idt, $statet, $directiont)> for $idi { fn from(tuple: ($idt, $statet, $directiont)) -> Self { let (id, state, direction) = tuple; Id { id, state, direction } } } $crate::as_item! { #[derive(Debug, PartialEq, Clone)] pub enum $packett { $($nam($body)),*, } } $crate::as_item! { #[derive(Debug, PartialEq)] pub enum $rawpackett<'a> { $($nam($rawdt<'a, $body>)),*, } } impl crate::protocol::Packet<$idi> for $packett { fn id(&self) -> $idi { use self::$packett::*; use self::$statet::*; use self::$directiont::*; match self { $($nam(_) => ($id, $state, $direction)),* }.into() } fn mc_deserialize(raw: crate::protocol::RawPacket<$idi>) -> Result { use self::$packett::*; use self::$statet::*; use self::$directiont::*; use crate::protocol::PacketErr::*; use crate::{Deserialize, Deserialized}; let id = raw.id; let data = raw.data; match (id.id, id.state, id.direction) { $(($id, $state, $direction) => { let Deserialized { value: body, data: rest } = $body::mc_deserialize(data).map_err(DeserializeFailed)?; if !rest.is_empty() { Err(ExtraData(rest.to_vec())) } else { Ok($nam(body)) } }),*, other => Err(UnknownId(other.0)), } } } impl crate::Serialize for $packett { fn mc_serialize(&self, to: &mut S) -> crate::SerializeResult { use self::$packett::*; match self { $($nam(body) => to.serialize_other(body)),+ } } } impl $packett { pub fn describe() -> crate::protocol::ProtocolSpec { crate::protocol::ProtocolSpec { name: stringify!($packett).to_owned(), packets: alloc::vec!( $(crate::protocol::ProtocolPacketSpec{ state: stringify!($state).to_owned(), direction: stringify!($direction).to_owned(), id: $id, name: stringify!($nam).to_owned(), body_struct: stringify!($body).to_owned(), fields: alloc::vec!( $(crate::protocol::ProtocolPacketField{ name: stringify!($fnam).to_owned(), kind: stringify!($ftyp).to_owned(), }),* ) }),*, ) } } } #[cfg(feature = "std")] impl<'a> std::convert::TryFrom> for $rawpackett<'a> { type Error = crate::protocol::PacketErr; fn try_from(value: crate::protocol::RawPacket<'a, $idi>) -> Result { use self::$rawpackett::*; use self::$statet::*; use self::$directiont::*; use crate::protocol::PacketErr::*; #[cfg(feature = "std")] use std::marker; #[cfg(not(feature = "std"))] use no_std_compat::marker; match (value.id.id, value.id.state, value.id.direction) { $(($id, $state, $direction) => Ok($nam($rawdt { data: value.data, _typ: marker::PhantomData, }))),*, other => Err(UnknownId(other.0)) } } } #[cfg(feature = "std")] impl<'a> std::convert::Into> for $rawpackett<'a> { fn into(self) -> crate::protocol::RawPacket<'a, $idi> { self.into_raw_packet() } } impl<'a> $rawpackett<'a> { fn into_raw_packet(self) -> crate::protocol::RawPacket<'a, $idi> { crate::protocol::RawPacket { id: self.id(), data: self.bytes(), } } } #[cfg(feature = "std")] impl<'a> std::convert::Into<&'a [u8]> for $rawpackett<'a> { fn into(self) -> &'a [u8] { use self::$rawpackett::*; match self { $($nam(bod) => bod.data),* } } } impl<'a> $rawpackett<'a> { pub fn id(&self) -> $idi { use self::$rawpackett::*; use self::$statet::*; use self::$directiont::*; match self { $($nam(_) => ($id, $state, $direction)),* }.into() } pub fn deserialize(self) -> Result<$packett, crate::protocol::PacketErr> { use crate::protocol::Packet; $packett::mc_deserialize(self.into_raw_packet()) } pub fn bytes(&self) -> &'a [u8] { use self::$rawpackett::*; match self { $($nam(bod) => bod.data),* } } } #[cfg(feature = "std")] #[derive(PartialEq, Debug)] pub struct $rawdt<'a, T> { pub data: &'a [u8], _typ: std::marker::PhantomData } #[cfg(not(feature = "std"))] #[derive(PartialEq, Debug)] pub struct $rawdt<'a, T> { pub data: &'a [u8], _typ: core::marker::PhantomData } impl<'a, T> $rawdt<'a, T> where T: crate::Deserialize { pub fn deserialize(&self) -> Result { use crate::protocol::PacketErr::*; let Deserialized { value: body, data: rest } = T::mc_deserialize(self.data).map_err(DeserializeFailed)?; if !rest.is_empty() { Err(ExtraData(rest.to_vec())) } else { Ok(body) } } } $($crate::__protocol_body_def_helper!($body { $($fnam: $ftyp),* });)* }; } #[macro_export] macro_rules! count_num { () => { 0 }; ($item: tt) => { 1 }; ($item: tt, $($rest: tt),+) => { 1 + count_num!($($rest),+) } } #[macro_export] macro_rules! proto_enum_deserialize_variant { ($data: ident, $ty: ident :: $nam: ident ($bod: ty)) => { Ok(<$bod>::mc_deserialize($data)?.map(move |body| $ty::$nam(body))) }; ($data: ident, $ty: ident :: $nam: ident) => { Deserialized::ok($ty::$nam, $data) }; } #[macro_export] macro_rules! instead_of_ident { ($ident: tt, $replacement: tt) => { $replacement } } #[macro_export] macro_rules! proto_enum_with_type { ($typ: ty, $typname: ident, $(($bval: literal, $nam: ident $(($bod: ty))?)),*) => { $crate::as_item! { #[derive(PartialEq, Clone, Debug)] pub enum $typname { $($nam $(($bod))?),* } } impl Serialize for $typname { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let id_to_serialize: $typ = match self { $($typname::$nam$((instead_of_ident!($bod, _)))? => $bval),* }.into(); to.serialize_other(&id_to_serialize)?; self.serialize_body(to) } } impl Deserialize for $typname { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { <$typ>::mc_deserialize(data)?.and_then(move |id, rest| { Self::deserialize_with_id(id, rest) }) } } impl $typname { pub fn deserialize_with_id<'a>(id: $typ, data: &'a[u8]) -> DeserializeResult<'a, Self> { match id.into() { $($bval => proto_enum_deserialize_variant!(data, $typname::$nam $(($bod))?)),*, other => { return Err(DeserializeErr::CannotUnderstandValue(alloc::format!("invalid {} {:?}", stringify!($typname), other))) } } } pub fn name(&self) -> &str { match self { $($typname::$nam$((instead_of_ident!($bod, _)))? => stringify!($nam)),* } } pub fn id(&self) -> $typ { match self { $($typname::$nam$((instead_of_ident!($bod, _)))? => $bval.into()),* } } #[allow(unused_variables)] pub fn serialize_body(&self, to: &mut S) -> SerializeResult { match &self { $($typname::$nam$((instead_of_ident!($bod, bod)))? => { $(to.serialize_other(instead_of_ident!($bod, bod))?;)? Ok(()) }),* } } } #[cfg(all(test, feature = "std"))] impl TestRandom for $typname { fn test_gen_random() -> Self { let mut idx: usize = (rand::random::() % (count_num!($($bval),+))) + 1; $( idx -= 1; if idx == 0 { return $typname::$nam$((<$bod>::test_gen_random()))?; } )+ panic!("cannot generate random {}", stringify!($typname)); } } } } #[macro_export] macro_rules! proto_byte_enum { ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => { proto_enum_with_type!(u8, $typname, $(($bval, $nam $(($bod))?)),*); } } #[macro_export] macro_rules! proto_varint_enum { ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => { proto_enum_with_type!(VarInt, $typname, $(($bval, $nam $(($bod))?)),*); } } #[macro_export] macro_rules! proto_int_enum { ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => { proto_enum_with_type!(i32, $typname, $(($bval, $nam $(($bod))?)),*); } } #[macro_export] macro_rules! proto_str_enum { ($typname: ident, $($sval: literal :: $nam: ident $(($bod: ident))?),*) => { crate::as_item! { #[derive(PartialEq, Clone, Debug)] pub enum $typname { $($nam $(($bod))?),* } } impl Serialize for $typname { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let name = self.name().to_owned(); to.serialize_other(&name)?; self.serialize_body(to) } } impl Deserialize for $typname { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { String::mc_deserialize(data)?.and_then(move |name, rest| { Self::deserialize_with_id(name.as_str(), rest) }) } } impl $typname { pub fn name(&self) -> &str { match self { $($typname::$nam$((instead_of_ident!($bod, _)))? => $sval),+, } } pub fn id(&self) -> String { self.name().to_owned() } pub fn deserialize_with_id<'a>(name: &str, data: &'a[u8]) -> DeserializeResult<'a, Self> { match name { $($sval => proto_enum_deserialize_variant!(data, $typname::$nam $(($bod))?)),*, other => Err(DeserializeErr::CannotUnderstandValue(alloc::format!("invalid {} ident '{}'", stringify!($typname), other))) } } #[allow(unused_variables)] pub fn serialize_body(&self, to: &mut S) -> SerializeResult { match &self { $($typname::$nam$((instead_of_ident!($bod, bod)))? => { $(to.serialize_other(instead_of_ident!($bod, bod))?;)? Ok(()) }),* } } } impl From<&$typname> for String { fn from(arg: &$typname) -> Self { arg.name().to_owned() } } impl From<$typname> for String { fn from(arg: $typname) -> Self { arg.name().to_owned() } } #[cfg(all(test, feature = "std"))] impl TestRandom for $typname { fn test_gen_random() -> Self { let mut idx: usize = (rand::random::() % (count_num!($($nam),+))) + 1; $( idx -= 1; if idx == 0 { return $typname::$nam$(($bod::test_gen_random()))?; } )+ panic!("cannot generate random {}", stringify!($typname)); } } } } #[macro_export] macro_rules! proto_byte_flag { ($typname: ident, $($bval: literal :: $nam: ident),*) => { #[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] pub struct $typname(pub u8); impl $typname { $(paste::paste! { pub fn [](&self) -> bool { self.0 & $bval != 0 } })* $(paste::paste! { pub fn [](&mut self, value: bool) { if value { self.0 |= $bval; } else { self.0 ^= $bval; } } })* $(paste::paste! { pub fn [](mut self, value: bool) -> Self { if value { self.0 |= $bval; } else { self.0 ^= $bval; } self } })* } impl Serialize for $typname { fn mc_serialize(&self, to: &mut S) -> SerializeResult { to.serialize_byte(self.0) } } impl Deserialize for $typname { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { Ok(u8::mc_deserialize(data)?.map(move |b| $typname(b))) } } #[cfg(all(test, feature = "std"))] impl TestRandom for $typname { fn test_gen_random() -> Self { let mut out = <$typname>::default(); $(paste::paste! { out.[](rand::random::()); })+ out } } } } #[macro_export] macro_rules! counted_array_type { ($name: ident, $countert: ty, $tousize_fn: ident, $fromusize_fn: ident) => { #[derive(Debug, Clone, PartialEq)] pub struct $name where T: Debug + Clone + PartialEq, { pub data: Vec, } impl Serialize for $name where T: Serialize + Debug + Clone + PartialEq, { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let count: $countert = $fromusize_fn(self.data.len()); to.serialize_other(&count)?; for entry in &self.data { to.serialize_other(entry)?; } Ok(()) } } impl Deserialize for $name where T: Deserialize + Debug + Clone + PartialEq, { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { let Deserialized { value: raw_count, mut data, } = <$countert>::mc_deserialize(data)?; let count: usize = $tousize_fn(raw_count); let mut out = Vec::with_capacity(count); for _ in 0..count { let Deserialized { value: next, data: rest, } = T::mc_deserialize(data)?; data = rest; out.push(next); } Deserialized::ok(Self { data: out }, data) } } impl Into> for $name where T: Debug + Clone + PartialEq, { fn into(self) -> Vec { self.data } } impl From> for $name where T: Debug + Clone + PartialEq, { fn from(data: Vec) -> Self { Self { data } } } impl<'a, T> IntoIterator for &'a mut $name where T: Debug + Clone + PartialEq, { type Item = &'a mut T; type IntoIter = alloc::slice::IterMut<'a, T>; fn into_iter(self) -> Self::IntoIter { let data = &mut self.data; data.iter_mut() } } impl<'a, T> IntoIterator for &'a $name where T: Debug + Clone + PartialEq, { type Item = &'a T; type IntoIter = alloc::slice::Iter<'a, T>; fn into_iter(self) -> Self::IntoIter { let data = &self.data; data.iter() } } impl IntoIterator for $name where T: Debug + Clone + PartialEq, { type Item = T; type IntoIter = alloc::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.data.into_iter() } } #[cfg(all(test, feature = "std"))] impl TestRandom for $name where T: TestRandom + Debug + Clone + PartialEq, { fn test_gen_random() -> Self { let elem_count: usize = rand::random::() % 32; let mut out = Vec::with_capacity(elem_count); for _ in 0..elem_count { out.push(T::test_gen_random()); } Self { data: out } } } }; }