use std::{
fmt,
io::{self, Read, Write},
};
use crate::{
io::{LimitedReadFrom, ReadFrom, WriteTo},
message::Message,
packet::Command,
var_type::{VarInt, VarStr},
};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Fatal(u64);
impl fmt::Display for Fatal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Fatal {
pub fn new(value: u64) -> Self {
Self(value)
}
pub fn as_u64(self) -> u64 {
self.0
}
}
impl From<u64> for Fatal {
fn from(value: u64) -> Self {
Self(value)
}
}
impl WriteTo for Fatal {
fn write_to(&self, w: &mut dyn Write) -> io::Result<()> {
VarInt::new(self.0).write_to(w)
}
}
impl ReadFrom for Fatal {
fn read_from(r: &mut dyn Read) -> io::Result<Self>
where
Self: Sized,
{
Ok(Self(VarInt::read_from(r)?.as_u64()))
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct ErrorText(VarStr);
impl ErrorText {
pub fn new(bytes: Vec<u8>) -> Self {
Self(VarStr::new(bytes))
}
}
impl fmt::Display for ErrorText {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<Vec<u8>> for ErrorText {
fn from(bytes: Vec<u8>) -> Self {
Self(bytes.into())
}
}
impl WriteTo for ErrorText {
fn write_to(&self, w: &mut dyn Write) -> io::Result<()> {
self.0.write_to(w)
}
}
impl LimitedReadFrom for ErrorText {
fn limited_read_from(r: &mut dyn Read, max_len: usize) -> io::Result<Self>
where
Self: Sized,
{
Ok(Self(VarStr::limited_read_from(r, max_len)?))
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Error {
fatal: Fatal,
ban_time: VarInt,
inventory_vector: VarStr,
error_text: ErrorText,
}
impl Error {
pub fn new(fatal: Fatal, error_text: ErrorText) -> Self {
Self {
fatal,
ban_time: 0u64.into(),
inventory_vector: b"".to_vec().into(),
error_text,
}
}
pub fn fatal(&self) -> Fatal {
self.fatal
}
pub fn error_text(&self) -> &ErrorText {
&self.error_text
}
}
impl WriteTo for Error {
fn write_to(&self, w: &mut dyn Write) -> io::Result<()> {
self.fatal.write_to(w)?;
self.ban_time.write_to(w)?;
self.inventory_vector.write_to(w)?;
self.error_text.write_to(w)?;
Ok(())
}
}
impl ReadFrom for Error {
fn read_from(r: &mut dyn Read) -> io::Result<Self>
where
Self: Sized,
{
const MAX_VAR_STR_LENGTH: usize = 5000;
Ok(Self {
fatal: Fatal::read_from(r)?,
ban_time: VarInt::read_from(r)?,
inventory_vector: VarStr::limited_read_from(r, MAX_VAR_STR_LENGTH)?,
error_text: ErrorText::limited_read_from(r, MAX_VAR_STR_LENGTH)?,
})
}
}
impl Message for Error {
const COMMAND: Command = Command::ERROR;
}
#[test]
fn test_error_write_to() {
let test = Error::new(1u64.into(), b"hello".to_vec().into());
let mut bytes = Vec::new();
test.write_to(&mut bytes).unwrap();
let expected = [1, 0, 0, 5, b'h', b'e', b'l', b'l', b'o'];
assert_eq!(bytes, expected.to_vec());
}
#[test]
fn test_error_read_from() {
use std::io::Cursor;
let mut bytes = Cursor::new([1, 0, 0, 5, b'h', b'e', b'l', b'l', b'o']);
let test = Error::read_from(&mut bytes).unwrap();
let expected = Error::new(1u64.into(), b"hello".to_vec().into());
assert_eq!(test, expected);
}