Add macros to impl concentrate enum and json

This commit is contained in:
vagola 2020-01-02 15:25:22 +03:00
parent f43592c01f
commit a4b7f100a8
6 changed files with 114 additions and 98 deletions

View File

@ -33,7 +33,7 @@ fn impl_encoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 {
let name = &field.ident; let name = &field.ident;
quote! { quote! {
Encoder::encode(&self.#name, writer); crate::Encoder::encode(&self.#name, writer);
} }
}); });
@ -49,7 +49,7 @@ fn impl_encoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 {
} }
fn impl_decoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 { fn impl_decoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 {
let decode = quote_field(fields, |field| { let decode = quote_field(fields, |_field| {
quote! { quote! {
todo!(); todo!();
} }

View File

@ -61,6 +61,7 @@
//! assert_eq!(expected_message, Message::from_json(json).unwrap()); //! assert_eq!(expected_message, Message::from_json(json).unwrap());
//! ``` //! ```
use crate::impl_json_encoder_decoder;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Error; use serde_json::Error;
@ -243,6 +244,8 @@ impl Message {
} }
} }
impl_json_encoder_decoder!(Message);
pub struct MessageBuilder { pub struct MessageBuilder {
current: Message, current: Message,
root: Option<Message>, root: Option<Message>,

View File

@ -1,9 +1,9 @@
use num_derive::{FromPrimitive, ToPrimitive}; use num_derive::{FromPrimitive, ToPrimitive};
use crate::chat::Message; use crate::chat::Message;
use crate::impl_enum_encoder_decoder;
use crate::DecodeError; use crate::DecodeError;
use crate::Decoder; use crate::Decoder;
use crate::Encoder;
use minecraft_protocol_derive::Packet; use minecraft_protocol_derive::Packet;
use nbt::CompoundTag; use nbt::CompoundTag;
use std::io::Read; use std::io::Read;
@ -111,6 +111,8 @@ pub enum MessagePosition {
HotBar, HotBar,
} }
impl_enum_encoder_decoder!(MessagePosition);
impl ClientBoundChatMessage { impl ClientBoundChatMessage {
pub fn new(message: Message, position: MessagePosition) -> GameClientBoundPacket { pub fn new(message: Message, position: MessagePosition) -> GameClientBoundPacket {
let chat_message = ClientBoundChatMessage { message, position }; let chat_message = ClientBoundChatMessage { message, position };
@ -139,6 +141,8 @@ pub enum GameMode {
Hardcore = 8, Hardcore = 8,
} }
impl_enum_encoder_decoder!(GameMode);
impl JoinGame { impl JoinGame {
pub fn new( pub fn new(
entity_id: u32, entity_id: u32,

View File

@ -6,8 +6,7 @@ use std::io;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::string::FromUtf8Error; use std::string::FromUtf8Error;
use byteorder::WriteBytesExt; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use byteorder::{BigEndian, ReadBytesExt};
use mc_varint::{VarIntRead, VarIntWrite}; use mc_varint::{VarIntRead, VarIntWrite};
use serde_json::error::Error as JsonError; use serde_json::error::Error as JsonError;
use uuid::parser::ParseError as UuidParseError; use uuid::parser::ParseError as UuidParseError;
@ -16,7 +15,6 @@ use crate::chat::Message;
use nbt::decode::TagDecodeError; use nbt::decode::TagDecodeError;
use nbt::CompoundTag; use nbt::CompoundTag;
use num_traits::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive, ToPrimitive};
use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
pub mod chat; pub mod chat;
@ -137,23 +135,8 @@ trait Decoder {
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError>; fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError>;
} }
/// Trait adds additional helper methods for `Read` to read protocol data.
trait PacketRead {
fn read_bool(&mut self) -> Result<bool, DecodeError>;
fn read_string(&mut self, max_length: u32) -> Result<String, DecodeError>;
fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError>;
fn read_chat_message(&mut self) -> Result<Message, DecodeError>;
fn read_enum<T: FromPrimitive>(&mut self) -> Result<T, DecodeError>;
fn read_compound_tag(&mut self) -> Result<CompoundTag, DecodeError>;
}
/// Trait adds additional helper methods for `Write` to write protocol data. /// Trait adds additional helper methods for `Write` to write protocol data.
trait PacketWrite { trait EncoderWriteExt {
fn write_bool(&mut self, value: bool) -> Result<(), EncodeError>; fn write_bool(&mut self, value: bool) -> Result<(), EncodeError>;
fn write_string(&mut self, value: &str, max_length: u32) -> Result<(), EncodeError>; fn write_string(&mut self, value: &str, max_length: u32) -> Result<(), EncodeError>;
@ -167,57 +150,22 @@ trait PacketWrite {
fn write_compound_tag(&mut self, value: &CompoundTag) -> Result<(), EncodeError>; fn write_compound_tag(&mut self, value: &CompoundTag) -> Result<(), EncodeError>;
} }
impl<R: Read> PacketRead for R { /// Trait adds additional helper methods for `Read` to read protocol data.
fn read_bool(&mut self) -> Result<bool, DecodeError> { trait DecoderReadExt {
match self.read_u8()? { fn read_bool(&mut self) -> Result<bool, DecodeError>;
0 => Ok(false),
1 => Ok(true),
_ => Err(DecodeError::NonBoolValue),
}
}
fn read_string(&mut self, max_length: u32) -> Result<String, DecodeError> { fn read_string(&mut self, max_length: u32) -> Result<String, DecodeError>;
let length = self.read_var_i32()? as u32;
if length > max_length as u32 { fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError>;
return Err(DecodeError::StringTooLong { length, max_length });
}
let mut buf = vec![0; length as usize]; fn read_chat_message(&mut self) -> Result<Message, DecodeError>;
self.read_exact(&mut buf)?;
Ok(String::from_utf8(buf)?) fn read_enum<T: FromPrimitive>(&mut self) -> Result<T, DecodeError>;
}
fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError> { fn read_compound_tag(&mut self) -> Result<CompoundTag, DecodeError>;
let length = self.read_var_i32()?;
let mut buf = vec![0; length as usize];
self.read_exact(&mut buf)?;
Ok(buf)
}
fn read_chat_message(&mut self) -> Result<Message, DecodeError> {
let json = self.read_string(STRING_MAX_LENGTH)?;
let message = Message::from_json(&json)?;
Ok(message)
}
fn read_enum<T: FromPrimitive>(&mut self) -> Result<T, DecodeError> {
let type_id = self.read_u8()?;
let result = FromPrimitive::from_u8(type_id);
result.ok_or_else(|| DecodeError::UnknownEnumType { type_id })
}
fn read_compound_tag(&mut self) -> Result<CompoundTag, DecodeError> {
Ok(nbt::decode::read_compound_tag(self)?)
}
} }
impl<W: Write> PacketWrite for W { impl<W: Write> EncoderWriteExt for W {
fn write_bool(&mut self, value: bool) -> Result<(), EncodeError> { fn write_bool(&mut self, value: bool) -> Result<(), EncodeError> {
if value { if value {
self.write_u8(1)?; self.write_u8(1)?;
@ -266,7 +214,55 @@ impl<W: Write> PacketWrite for W {
} }
} }
// TODO: Replace primitive impls with macros. impl<R: Read> DecoderReadExt for R {
fn read_bool(&mut self) -> Result<bool, DecodeError> {
match self.read_u8()? {
0 => Ok(false),
1 => Ok(true),
_ => Err(DecodeError::NonBoolValue),
}
}
fn read_string(&mut self, max_length: u32) -> Result<String, DecodeError> {
let length = self.read_var_i32()? as u32;
if length > max_length as u32 {
return Err(DecodeError::StringTooLong { length, max_length });
}
let mut buf = vec![0; length as usize];
self.read_exact(&mut buf)?;
Ok(String::from_utf8(buf)?)
}
fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError> {
let length = self.read_var_i32()?;
let mut buf = vec![0; length as usize];
self.read_exact(&mut buf)?;
Ok(buf)
}
fn read_chat_message(&mut self) -> Result<Message, DecodeError> {
let json = self.read_string(STRING_MAX_LENGTH)?;
let message = Message::from_json(&json)?;
Ok(message)
}
fn read_enum<T: FromPrimitive>(&mut self) -> Result<T, DecodeError> {
let type_id = self.read_u8()?;
let result = FromPrimitive::from_u8(type_id);
result.ok_or_else(|| DecodeError::UnknownEnumType { type_id })
}
fn read_compound_tag(&mut self) -> Result<CompoundTag, DecodeError> {
Ok(nbt::decode::read_compound_tag(self)?)
}
}
impl Encoder for u8 { impl Encoder for u8 {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
@ -366,20 +362,6 @@ impl Decoder for bool {
} }
} }
impl<T: ToPrimitive> Encoder for T {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_enum(self)?)
}
}
impl<T: ToPrimitive> Decoder for T {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_enum())
}
}
impl Encoder for Vec<u8> { impl Encoder for Vec<u8> {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_byte_array(self)?) Ok(writer.write_byte_array(self)?)
@ -404,8 +386,8 @@ impl Decoder for Uuid {
type Output = Self; type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let buf = [0; 16]; let mut buf = [0; 16];
reader.read_exact(&buf)?; reader.read_exact(&mut buf)?;
Ok(Uuid::from_bytes(buf)) Ok(Uuid::from_bytes(buf))
} }
@ -453,20 +435,45 @@ impl Decoder for Vec<CompoundTag> {
} }
} }
impl<T: Serialize> Encoder for T { #[macro_export]
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { macro_rules! impl_enum_encoder_decoder (
let json = serde_json::to_string(self)?; ($ty: ident) => (
writer.write_string(&json, STRING_MAX_LENGTH)?; impl crate::Encoder for $ty {
fn encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), crate::EncodeError> {
Ok(crate::EncoderWriteExt::write_enum(writer, self)?)
}
}
Ok(()) impl crate::Decoder for $ty {
} type Output = Self;
}
impl<'de, T: Deserialize<'de>> Decoder for T { fn decode<R: std::io::Read>(reader: &mut R) -> Result<Self::Output, crate::DecodeError> {
type Output = Self; Ok(crate::DecoderReadExt::read_enum(reader)?)
}
}
);
);
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { #[macro_export]
let json = reader.read_string(STRING_MAX_LENGTH)?; macro_rules! impl_json_encoder_decoder (
serde_json::from_str(&json)? ($ty: ident) => (
} impl crate::Encoder for $ty {
} fn encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), crate::EncodeError> {
let json = serde_json::to_string(self)?;
crate::EncoderWriteExt::write_string(writer, &json, crate::STRING_MAX_LENGTH)?;
Ok(())
}
}
impl crate::Decoder for $ty {
type Output = Self;
fn decode<R: std::io::Read>(reader: &mut R) -> Result<Self::Output, crate::DecodeError> {
let json = crate::DecoderReadExt::read_string(reader, crate::STRING_MAX_LENGTH)?;
Ok(serde_json::from_str(&json)?)
}
}
);
);

View File

@ -1,7 +1,6 @@
use crate::chat::Message; use crate::chat::Message;
use crate::DecodeError; use crate::DecodeError;
use crate::Decoder; use crate::Decoder;
use crate::Encoder;
use std::io::Read; use std::io::Read;
use uuid::Uuid; use uuid::Uuid;

View File

@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::chat::Message; use crate::chat::Message;
use crate::impl_json_encoder_decoder;
use crate::DecodeError; use crate::DecodeError;
use crate::Decoder; use crate::Decoder;
use minecraft_protocol_derive::Packet; use minecraft_protocol_derive::Packet;
@ -104,6 +105,8 @@ pub struct StatusResponse {
pub server_status: ServerStatus, pub server_status: ServerStatus,
} }
impl_json_encoder_decoder!(ServerStatus);
impl StatusResponse { impl StatusResponse {
pub fn new(server_status: ServerStatus) -> StatusClientBoundPacket { pub fn new(server_status: ServerStatus) -> StatusClientBoundPacket {
let status_response = StatusResponse { server_status }; let status_response = StatusResponse { server_status };