From 71d82c53302738432ac3b52db03b42a4a09710a4 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Wed, 19 Oct 2022 01:52:02 -0700 Subject: [PATCH] Add `encoded_len` method to `Encode` trait. (#125) This allows packets to calculate their exact length up front. This isn't currently tested or being used for anything, but that will come in later changes. --- Cargo.toml | 2 +- packet_inspector/src/main.rs | 2 +- src/block.rs | 4 + src/block_pos.rs | 4 + src/entity/types.rs | 46 +++++++++ src/ident.rs | 4 + src/item.rs | 4 + src/protocol.rs | 192 +++++++++++++++++++++++++++++++++-- src/protocol/byte_angle.rs | 4 + src/protocol/codec.rs | 4 +- src/protocol/packets.rs | 26 ++++- src/protocol/packets/s2c.rs | 6 -- src/protocol/slot.rs | 11 ++ src/protocol/var_int.rs | 30 ++---- src/protocol/var_long.rs | 9 ++ src/text.rs | 31 +++--- 16 files changed, 326 insertions(+), 53 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1da0b09..11e822a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ sha2 = "0.10.6" thiserror = "1.0.35" url = { version = "2.2.2", features = ["serde"] } uuid = { version = "1.1.2", features = ["serde"] } -valence_nbt = "0.2.0" +valence_nbt = "0.3.0" vek = "0.15.8" [dependencies.tokio] diff --git a/packet_inspector/src/main.rs b/packet_inspector/src/main.rs index 2947a99..dad91b7 100644 --- a/packet_inspector/src/main.rs +++ b/packet_inspector/src/main.rs @@ -78,7 +78,7 @@ impl Cli { let len = VarInt(read.packet_buf().len() as i32); len.encode(&mut len_buf.as_mut_slice())?; - write.write_all(&len_buf[..len.written_size()]).await?; + write.write_all(&len_buf[..len.encoded_len()]).await?; write.write_all(read.packet_buf()).await?; pkt diff --git a/src/block.rs b/src/block.rs index 04a371a..06bbf02 100644 --- a/src/block.rs +++ b/src/block.rs @@ -56,6 +56,10 @@ impl Encode for BlockState { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { VarInt(self.0 as i32).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(self.0 as i32).encoded_len() + } } impl Decode for BlockState { diff --git a/src/block_pos.rs b/src/block_pos.rs index 7c005ec..7fa9f94 100644 --- a/src/block_pos.rs +++ b/src/block_pos.rs @@ -58,6 +58,10 @@ impl Encode for BlockPos { _ => bail!("out of range: {self:?}"), } } + + fn encoded_len(&self) -> usize { + 8 + } } impl Decode for BlockPos { diff --git a/src/entity/types.rs b/src/entity/types.rs index bf7ba8f..6cc402a 100644 --- a/src/entity/types.rs +++ b/src/entity/types.rs @@ -27,6 +27,10 @@ impl Encode for OptionalInt { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { VarInt(self.0 as i32).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(self.0 as i32).encoded_len() + } } impl Decode for OptionalInt { @@ -54,6 +58,10 @@ impl Encode for EulerAngle { self.yaw.encode(w)?; self.roll.encode(w) } + + fn encoded_len(&self) -> usize { + self.pitch.encoded_len() + self.yaw.encoded_len() + self.roll.encoded_len() + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -70,6 +78,10 @@ impl Encode for Facing { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { VarInt(*self as i32).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(*self as i32).encoded_len() + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -105,6 +117,12 @@ impl Encode for VillagerData { VarInt(self.profession as i32).encode(w)?; VarInt(self.level).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(self.kind as i32).encoded_len() + + VarInt(self.profession as i32).encoded_len() + + VarInt(self.level).encoded_len() + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] @@ -162,6 +180,10 @@ impl Encode for Pose { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { VarInt(*self as i32).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(*self as i32).encoded_len() + } } /// The main hand of a player. @@ -176,6 +198,10 @@ impl Encode for MainArm { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { (*self as u8).encode(w) } + + fn encoded_len(&self) -> usize { + 1 + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] @@ -193,6 +219,10 @@ impl Encode for BoatKind { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { VarInt(*self as i32).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(*self as i32).encoded_len() + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] @@ -215,6 +245,10 @@ impl Encode for CatKind { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { VarInt(*self as i32).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(*self as i32).encoded_len() + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] @@ -229,6 +263,10 @@ impl Encode for FrogKind { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { VarInt(*self as i32).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(*self as i32).encoded_len() + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] @@ -270,6 +308,10 @@ impl Encode for PaintingKind { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { VarInt(*self as i32).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(*self as i32).encoded_len() + } } // TODO @@ -282,4 +324,8 @@ impl Encode for Particle { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { VarInt(*self as i32).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(*self as i32).encoded_len() + } } diff --git a/src/ident.rs b/src/ident.rs index be803ce..077bdfa 100644 --- a/src/ident.rs +++ b/src/ident.rs @@ -225,6 +225,10 @@ impl Encode for Ident { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { self.string.encode(w) } + + fn encoded_len(&self) -> usize { + self.string.encoded_len() + } } impl Decode for Ident diff --git a/src/item.rs b/src/item.rs index 4738692..0af5774 100644 --- a/src/item.rs +++ b/src/item.rs @@ -12,6 +12,10 @@ impl Encode for ItemKind { fn encode(&self, w: &mut impl std::io::Write) -> anyhow::Result<()> { VarInt(self.to_raw() as i32).encode(w) } + + fn encoded_len(&self) -> usize { + VarInt(self.to_raw() as i32).encoded_len() + } } impl Decode for ItemKind { diff --git a/src/protocol.rs b/src/protocol.rs index 565ab8c..2d5a64f 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -41,9 +41,17 @@ mod var_long; /// Types that can be written to the Minecraft protocol. pub trait Encode { - /// This function must be pure. In other words, consecutive calls to - /// `encode` must write the exact same sequence of bytes. fn encode(&self, w: &mut impl Write) -> anyhow::Result<()>; + + /// Returns the number of bytes that will be written when [`Self::encode`] + /// is called. + /// + /// If [`Self::encode`] results in `Ok`, the exact number of bytes reported + /// by this function must be written to the writer argument. + /// + /// If the result is `Err`, then the number of written bytes must be less + /// than or equal to the count returned by this function. + fn encoded_len(&self) -> usize; } /// Types that can be read from the Minecraft protocol. @@ -58,6 +66,10 @@ impl Encode for () { fn encode(&self, _w: &mut impl Write) -> anyhow::Result<()> { Ok(()) } + + fn encoded_len(&self) -> usize { + 0 + } } impl Decode for () { @@ -71,6 +83,10 @@ impl Encode for (T, U) { self.0.encode(w)?; self.1.encode(w) } + + fn encoded_len(&self) -> usize { + self.0.encoded_len() + self.1.encoded_len() + } } impl Decode for (T, U) { @@ -83,6 +99,10 @@ impl Encode for &T { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { (*self).encode(w) } + + fn encoded_len(&self) -> usize { + (*self).encoded_len() + } } impl Encode for bool { @@ -90,6 +110,10 @@ impl Encode for bool { w.write_u8(*self as u8)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 1 + } } impl Decode for bool { @@ -105,6 +129,10 @@ impl Encode for u8 { w.write_u8(*self)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 1 + } } impl Decode for u8 { @@ -118,6 +146,10 @@ impl Encode for i8 { w.write_i8(*self)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 1 + } } impl Decode for i8 { @@ -131,6 +163,10 @@ impl Encode for u16 { w.write_u16::(*self)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 2 + } } impl Decode for u16 { @@ -144,6 +180,10 @@ impl Encode for i16 { w.write_i16::(*self)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 2 + } } impl Decode for i16 { @@ -157,6 +197,10 @@ impl Encode for u32 { w.write_u32::(*self)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 4 + } } impl Decode for u32 { @@ -170,6 +214,10 @@ impl Encode for i32 { w.write_i32::(*self)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 4 + } } impl Decode for i32 { @@ -183,6 +231,10 @@ impl Encode for u64 { w.write_u64::(*self)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 8 + } } impl Decode for u64 { @@ -196,6 +248,10 @@ impl Encode for i64 { w.write_i64::(*self)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 8 + } } impl Decode for i64 { @@ -214,6 +270,10 @@ impl Encode for f32 { w.write_f32::(*self)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 4 + } } impl Decode for f32 { fn decode(r: &mut &[u8]) -> anyhow::Result { @@ -233,6 +293,10 @@ impl Encode for f64 { w.write_f64::(*self)?; Ok(()) } + + fn encoded_len(&self) -> usize { + 8 + } } impl Decode for f64 { @@ -253,6 +317,13 @@ impl Encode for Option { None => false.encode(w), } } + + fn encoded_len(&self) -> usize { + 1 + match self { + Some(t) => t.encoded_len(), + None => 0, + } + } } impl Decode for Option { @@ -269,6 +340,10 @@ impl Encode for Box { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { self.as_ref().encode(w) } + + fn encoded_len(&self) -> usize { + self.as_ref().encoded_len() + } } impl Decode for Box { @@ -281,6 +356,10 @@ impl Encode for Box { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { encode_string_bounded(self, 0, 32767, w) } + + fn encoded_len(&self) -> usize { + self.as_ref().encoded_len() + } } impl Decode for Box { @@ -326,6 +405,10 @@ where self.0.encode(w) } + + fn encoded_len(&self) -> usize { + self.0.encoded_len() + } } impl Decode for BoundedInt @@ -349,12 +432,20 @@ impl Encode for str { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { encode_string_bounded(self, 0, 32767, w) } + + fn encoded_len(&self) -> usize { + VarInt(self.len().try_into().unwrap_or(i32::MAX)).encoded_len() + self.len() + } } impl Encode for String { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { self.as_str().encode(w) } + + fn encoded_len(&self) -> usize { + self.as_str().encoded_len() + } } impl Decode for String { @@ -367,6 +458,10 @@ impl<'a> Encode for Cow<'a, str> { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { self.as_ref().encode(w) } + + fn encoded_len(&self) -> usize { + self.as_ref().encoded_len() + } } impl Decode for Cow<'static, str> { @@ -398,6 +493,10 @@ impl Encode for BoundedString { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { encode_string_bounded(&self.0, MIN, MAX, w) } + + fn encoded_len(&self) -> usize { + self.0.encoded_len() + } } impl Decode for BoundedString { @@ -412,10 +511,25 @@ impl From for BoundedString Encode for Vec { +impl<'a, T: Encode> Encode for &'a [T] { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { encode_array_bounded(self, 0, usize::MAX, w) } + + fn encoded_len(&self) -> usize { + let elems_len: usize = self.iter().map(|a| a.encoded_len()).sum(); + VarInt(self.len().try_into().unwrap_or(i32::MAX)).encoded_len() + elems_len + } +} + +impl Encode for Vec { + fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { + self.as_slice().encode(w) + } + + fn encoded_len(&self) -> usize { + self.as_slice().encoded_len() + } } impl Decode for Vec { @@ -428,6 +542,10 @@ impl Encode for Box<[T]> { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { encode_array_bounded(self, 0, usize::MAX, w) } + + fn encoded_len(&self) -> usize { + self.as_ref().encoded_len() + } } impl Decode for Box<[T]> { @@ -438,19 +556,31 @@ impl Decode for Box<[T]> { impl Encode for [T; N] { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { - encode_array_bounded(self, N, N, w) + // for t in self { + // t.encode(w)?; + // } + // + // Ok(()) + + self.as_slice().encode(w) + + // encode_array_bounded(self, N, N, w) + } + + fn encoded_len(&self) -> usize { + self.iter().map(Encode::encoded_len).sum() } } impl Decode for [T; N] { fn decode(r: &mut &[u8]) -> anyhow::Result { + ensure!(VarInt::decode(r)?.0 == N as i32); + let mut elems = ArrayVec::new(); for _ in 0..N { elems.push(T::decode(r)?); } - elems - .into_inner() - .map_err(|_| unreachable!("mismatched array size")) + elems.into_inner().map_err(|_| unreachable!()) } } @@ -459,6 +589,10 @@ impl Encode for Vec2 { self.x.encode(w)?; self.y.encode(w) } + + fn encoded_len(&self) -> usize { + self.x.encoded_len() + self.y.encoded_len() + } } impl Encode for Vec3 { @@ -467,6 +601,10 @@ impl Encode for Vec3 { self.y.encode(w)?; self.z.encode(w) } + + fn encoded_len(&self) -> usize { + self.x.encoded_len() + self.y.encoded_len() + self.z.encoded_len() + } } impl Encode for Vec4 { @@ -476,6 +614,10 @@ impl Encode for Vec4 { self.z.encode(w)?; self.w.encode(w) } + + fn encoded_len(&self) -> usize { + self.x.encoded_len() + self.y.encoded_len() + self.z.encoded_len() + self.w.encoded_len() + } } impl Decode for Vec2 { @@ -506,12 +648,16 @@ impl Decode for Vec4 { /// If the array is not in bounds, an error is generated while /// encoding or decoding. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash, Debug)] -pub struct BoundedArray(pub Vec); +pub struct BoundedArray(pub Vec); impl Encode for BoundedArray { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { encode_array_bounded(&self.0, MIN, MAX, w) } + + fn encoded_len(&self) -> usize { + self.0.as_slice().encoded_len() + } } impl Decode for BoundedArray { @@ -531,6 +677,10 @@ impl Encode for Uuid { w.write_u128::(self.as_u128())?; Ok(()) } + + fn encoded_len(&self) -> usize { + 16 + } } impl Decode for Uuid { @@ -543,6 +693,10 @@ impl Encode for Compound { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { Ok(nbt::to_binary_writer(w, self, "")?) } + + fn encoded_len(&self) -> usize { + self.binary_encoded_len("") + } } impl Decode for Compound { @@ -554,7 +708,11 @@ impl Decode for Compound { impl Encode for BitVec { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { - encode_array_bounded(self.as_raw_slice(), 0, usize::MAX, w) + self.as_raw_slice().encode(w) + } + + fn encoded_len(&self) -> usize { + self.as_raw_slice().encoded_len() } } @@ -567,7 +725,11 @@ impl Decode for BitVec { impl Encode for BitBox { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { - encode_array_bounded(self.as_raw_slice(), 0, usize::MAX, w) + self.as_raw_slice().encode(w) + } + + fn encoded_len(&self) -> usize { + self.as_raw_slice().encoded_len() } } @@ -593,7 +755,11 @@ impl Decode for RawBytes { impl Encode for RawBytes { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { - w.write_all(&self.0).map_err(|e| e.into()) + Ok(w.write_all(&self.0)?) + } + + fn encoded_len(&self) -> usize { + self.0.len() } } @@ -609,6 +775,10 @@ impl Encode for Option { } .encode(w) } + + fn encoded_len(&self) -> usize { + 4 + } } fn encode_array_bounded( diff --git a/src/protocol/byte_angle.rs b/src/protocol/byte_angle.rs index 8f62208..41a7d12 100644 --- a/src/protocol/byte_angle.rs +++ b/src/protocol/byte_angle.rs @@ -20,6 +20,10 @@ impl Encode for ByteAngle { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { self.0.encode(w) } + + fn encoded_len(&self) -> usize { + self.0.encoded_len() + } } impl Decode for ByteAngle { diff --git a/src/protocol/codec.rs b/src/protocol/codec.rs index db1c57c..9c71d70 100644 --- a/src/protocol/codec.rs +++ b/src/protocol/codec.rs @@ -55,7 +55,7 @@ impl Encoder { z.read_to_end(&mut self.compress_buf)?; - let data_len_len = VarInt(data_len as i32).written_size(); + let data_len_len = VarInt(data_len as i32).encoded_len(); let packet_len = data_len_len + self.compress_buf.len(); ensure!(packet_len <= MAX_PACKET_SIZE as usize, "bad packet length"); @@ -67,7 +67,7 @@ impl Encoder { self.buf.extend_from_slice(&self.compress_buf); self.compress_buf.clear(); } else { - let packet_len = VarInt(0).written_size() + data_len; + let packet_len = VarInt(0).encoded_len() + data_len; ensure!(packet_len <= MAX_PACKET_SIZE as usize, "bad packet length"); diff --git a/src/protocol/packets.rs b/src/protocol/packets.rs index 14529a3..4aaa889 100644 --- a/src/protocol/packets.rs +++ b/src/protocol/packets.rs @@ -15,7 +15,6 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use vek::Vec3; -// use {def_bitfield, def_enum, def_struct}; use crate::block_pos::BlockPos; use crate::ident::Ident; use crate::nbt::Compound; @@ -82,6 +81,13 @@ macro_rules! def_struct { )* Ok(()) } + + fn encoded_len(&self) -> usize { + 0 + $( + + self.$field.encoded_len() + )* + } } impl Decode for $name { @@ -152,6 +158,20 @@ macro_rules! def_enum { _ => unreachable!("uninhabited enum?") } } + + fn encoded_len(&self) -> usize { + match self { + $( + if_typ_is_empty_pat!($($typ)?, $name::$variant, $name::$variant(val)) => { + <$tag_ty>::encoded_len(&$lit.into()) + + if_typ_is_empty_expr!($($typ)?, 0, Encode::encoded_len(val)) + } + )* + + #[allow(unreachable_patterns)] + _ => unreachable!("uninhabited enum?") + } + } } impl Decode for $name { @@ -264,6 +284,10 @@ macro_rules! def_bitfield { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { self.0.encode(w) } + + fn encoded_len(&self) -> usize { + self.0.encoded_len() + } } impl Decode for $name { diff --git a/src/protocol/packets/s2c.rs b/src/protocol/packets/s2c.rs index 1a186e0..d6112b7 100644 --- a/src/protocol/packets/s2c.rs +++ b/src/protocol/packets/s2c.rs @@ -366,12 +366,6 @@ pub mod play { } } - // #[derive(Clone, Debug, Serialize, Deserialize)] - // pub struct ChunkDataHeightmaps { - // #[serde(rename = "MOTION_BLOCKING", with = "crate::nbt::long_array")] - // pub motion_blocking: Vec, - // } - def_struct! { ChunkDataBlockEntity { packed_xz: i8, diff --git a/src/protocol/slot.rs b/src/protocol/slot.rs index 9541903..d9417c1 100644 --- a/src/protocol/slot.rs +++ b/src/protocol/slot.rs @@ -26,6 +26,17 @@ impl Encode for Slot { } } } + + fn encoded_len(&self) -> usize { + match self { + None => 1, + Some(s) => { + 1 + s.item.encoded_len() + + 1 + + s.nbt.as_ref().map(|nbt| nbt.encoded_len()).unwrap_or(1) + } + } + } } impl Decode for Slot { diff --git a/src/protocol/var_int.rs b/src/protocol/var_int.rs index e1aea02..491def3 100644 --- a/src/protocol/var_int.rs +++ b/src/protocol/var_int.rs @@ -13,27 +13,12 @@ impl VarInt { /// The maximum number of bytes a VarInt could occupy when read from and /// written to the Minecraft protocol. pub const MAX_SIZE: usize = 5; - - /// The number of bytes this `VarInt` will occupy when written to the - /// Minecraft protocol. - pub const fn written_size(self) -> usize { - let val = self.0 as u32; - if val & 0b11110000_00000000_00000000_00000000 != 0 { - 5 - } else if val & 0b11111111_11100000_00000000_00000000 != 0 { - 4 - } else if val & 0b11111111_11111111_11000000_00000000 != 0 { - 3 - } else if val & 0b11111111_11111111_11111111_10000000 != 0 { - 2 - } else { - 1 - } - } } impl Encode for VarInt { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { + // TODO: optimize this. + let mut val = self.0 as u32; loop { if val & 0b11111111111111111111111110000000 == 0 { @@ -44,6 +29,13 @@ impl Encode for VarInt { val >>= 7; } } + + fn encoded_len(&self) -> usize { + match self.0 { + 0 => 1, + n => (31 - n.leading_zeros() as usize) / 7 + 1, + } + } } impl Decode for VarInt { @@ -85,7 +77,7 @@ mod tests { use super::*; #[test] - fn written_size_correct() { + fn encoded_len_correct() { let mut rng = thread_rng(); let mut buf = Vec::new(); @@ -96,7 +88,7 @@ mod tests { { buf.clear(); n.encode(&mut buf).unwrap(); - assert_eq!(buf.len(), n.written_size()); + assert_eq!(buf.len(), n.encoded_len()); } } diff --git a/src/protocol/var_long.rs b/src/protocol/var_long.rs index ffe2d2a..66553c9 100644 --- a/src/protocol/var_long.rs +++ b/src/protocol/var_long.rs @@ -17,6 +17,8 @@ impl VarLong { impl Encode for VarLong { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { + // TODO: optimize this. + let mut val = self.0 as u64; loop { if val & 0b1111111111111111111111111111111111111111111111111111111110000000 == 0 { @@ -27,6 +29,13 @@ impl Encode for VarLong { val >>= 7; } } + + fn encoded_len(&self) -> usize { + match self.0 { + 0 => 1, + n => (63 - n.leading_zeros() as usize) / 7 + 1, + } + } } impl Decode for VarLong { diff --git a/src/text.rs b/src/text.rs index 61d5723..cec6d82 100644 --- a/src/text.rs +++ b/src/text.rs @@ -112,17 +112,21 @@ impl Text { } /// Writes this text object as plain text to the provided writer. - pub fn write_plain(&self, w: &mut impl fmt::Write) -> fmt::Result { - match &self.content { - TextContent::Text { text } => w.write_str(text.as_ref())?, - TextContent::Translate { translate } => w.write_str(translate.as_ref())?, + pub fn write_plain(&self, mut w: impl fmt::Write) -> fmt::Result { + fn write_plain_impl(this: &Text, w: &mut impl fmt::Write) -> fmt::Result { + match &this.content { + TextContent::Text { text } => w.write_str(text.as_ref())?, + TextContent::Translate { translate } => w.write_str(translate.as_ref())?, + } + + for child in &this.extra { + write_plain_impl(child, w)?; + } + + Ok(()) } - for child in &self.extra { - child.write_plain(w)?; - } - - Ok(()) + write_plain_impl(self, &mut w) } /// Returns `true` if the text contains no characters. Returns `false` @@ -443,8 +447,8 @@ impl<'a, 'b> From<&'a Text> for Cow<'b, str> { } impl fmt::Display for Text { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", String::from(self)) + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.write_plain(f) } } @@ -452,6 +456,10 @@ impl Encode for Text { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { BoundedString::<0, 262144>(serde_json::to_string(self)?).encode(w) } + + fn encoded_len(&self) -> usize { + todo!("remove Encode impl on text and come up with solution") + } } impl Decode for Text { @@ -467,7 +475,6 @@ impl Default for TextContent { } } -#[allow(missing_docs)] impl Color { pub const AQUA: Color = Color::new(85, 255, 255); pub const BLACK: Color = Color::new(0, 0, 0);