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;
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 {
let decode = quote_field(fields, |field| {
let decode = quote_field(fields, |_field| {
quote! {
todo!();
}

View File

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

View File

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

View File

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

View File

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