Skip to content

Commit

Permalink
add codecs folder to git
Browse files Browse the repository at this point in the history
  • Loading branch information
Snowiiii committed Dec 21, 2024
1 parent 0633197 commit fd66790
Show file tree
Hide file tree
Showing 5 changed files with 496 additions and 0 deletions.
53 changes: 53 additions & 0 deletions pumpkin-protocol/src/codec/bit_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::num::NonZeroUsize;

use bytes::{Buf, BufMut};
use serde::{Serialize, Serializer};

use crate::bytebuf::ByteBuf;
use crate::bytebuf::ByteBufMut;

use super::{var_int::VarInt, Codec, DecodeError};

pub struct BitSet(pub VarInt, pub Vec<i64>);

impl Codec<BitSet> for BitSet {
/// The maximum size of the BitSet is `remaining / 8`.
const MAX_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(usize::MAX) };

fn written_size(&self) -> usize {
todo!()
}

fn encode(&self, write: &mut impl BufMut) {
write.put_var_int(&self.0);
for b in &self.1 {
write.put_i64(*b);
}
}

fn decode(read: &mut impl Buf) -> Result<Self, DecodeError> {
// read length
let length = read
.try_get_var_int()
.map_err(|_| DecodeError::Incomplete)?;
// vanilla uses remaining / 8
if length.0 as usize >= read.remaining() / 8 {
return Err(DecodeError::TooLarge);
}
let mut array: Vec<i64> = Vec::with_capacity(size_of::<i64>() * length.0 as usize);
for _ in 0..length.0 {
let long = read.try_get_i64().map_err(|_| DecodeError::Incomplete)?;
array.push(long);
}
Ok(BitSet(length, array))
}
}

impl Serialize for BitSet {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
todo!()
}
}
101 changes: 101 additions & 0 deletions pumpkin-protocol/src/codec/identifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use std::num::NonZeroUsize;

use bytes::{Buf, BufMut};
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};

use crate::bytebuf::{ByteBuf, ByteBufMut};

use super::{Codec, DecodeError};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Identifier {
pub namespace: String,
pub path: String,
}

impl Identifier {
pub fn vanilla(path: &str) -> Self {
Self {
namespace: "minecraft".to_string(),
path: path.to_string(),
}
}
}
impl Codec<Self> for Identifier {
/// The maximum number of bytes a `Identifer` is the same as for a normal String.
const MAX_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(i16::MAX as usize) };

fn written_size(&self) -> usize {
todo!()
}

fn encode(&self, write: &mut impl BufMut) {
write.put_string_len(&self.to_string(), Self::MAX_SIZE.get());
}

fn decode(read: &mut impl Buf) -> Result<Self, DecodeError> {
let identifer = read
.try_get_string_len(Self::MAX_SIZE.get())
.map_err(|_| DecodeError::Incomplete)?;
match identifer.split_once(":") {
Some((namespace, path)) => Ok(Identifier {
namespace: namespace.to_string(),
path: path.to_string(),
}),
None => Err(DecodeError::Incomplete),
}
}
}

impl Serialize for Identifier {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}

impl<'de> Deserialize<'de> for Identifier {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct IdentifierVisitor;

impl Visitor<'_> for IdentifierVisitor {
type Value = Identifier;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid Identifier (namespace:path)")
}

fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(&v)
}

fn visit_str<E>(self, identifer: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match identifer.split_once(":") {
Some((namespace, path)) => Ok(Identifier {
namespace: namespace.to_string(),
path: path.to_string(),
}),
None => Err(serde::de::Error::custom("Identifier can't be split")),
}
}
}
deserializer.deserialize_str(IdentifierVisitor)
}
}

impl std::fmt::Display for Identifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.namespace, self.path)
}
}
27 changes: 27 additions & 0 deletions pumpkin-protocol/src/codec/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use std::num::NonZeroUsize;

use bytes::{Buf, BufMut};
use thiserror::Error;

pub mod bit_set;
pub mod identifier;
pub mod var_int;
pub mod var_long;

pub trait Codec<T> {
const MAX_SIZE: NonZeroUsize;

fn written_size(&self) -> usize;

fn encode(&self, write: &mut impl BufMut);

fn decode(read: &mut impl Buf) -> Result<T, DecodeError>;
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)]
pub enum DecodeError {
#[error("Incomplete VarInt decode")]
Incomplete,
#[error("VarInt is too large")]
TooLarge,
}
157 changes: 157 additions & 0 deletions pumpkin-protocol/src/codec/var_int.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use std::{num::NonZeroUsize, ops::Deref};

use super::{Codec, DecodeError};
use bytes::{Buf, BufMut};
use serde::{
de::{SeqAccess, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};

pub type VarIntType = i32;

/**
* A variable-length integer type used by the Minecraft network protocol.
*/
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VarInt(pub VarIntType);

impl Codec<Self> for VarInt {
/// The maximum number of bytes a `VarInt` can occupy.
const MAX_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(5) };

/// Returns the exact number of bytes this varint will write when
/// [`Encode::encode`] is called, assuming no error occurs.
fn written_size(&self) -> usize {
match self.0 {
0 => 1,
n => (31 - n.leading_zeros() as usize) / 7 + 1,
}
}

fn encode(&self, write: &mut impl BufMut) {
let mut val = self.0;
for _ in 0..Self::MAX_SIZE.get() {
let b: u8 = val as u8 & 0b01111111;
val >>= 7;
write.put_u8(if val == 0 { b } else { b | 0b10000000 });
if val == 0 {
break;
}
}
}

fn decode(read: &mut impl Buf) -> Result<Self, DecodeError> {
let mut val = 0;
for i in 0..Self::MAX_SIZE.get() {
if !read.has_remaining() {
return Err(DecodeError::Incomplete);
}
let byte = read.get_u8();
val |= (i32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 {
return Ok(VarInt(val));
}
}
Err(DecodeError::TooLarge)
}
}

impl From<i32> for VarInt {
fn from(value: i32) -> Self {
VarInt(value)
}
}

impl From<u32> for VarInt {
fn from(value: u32) -> Self {
VarInt(value as i32)
}
}

impl From<u8> for VarInt {
fn from(value: u8) -> Self {
VarInt(value as i32)
}
}

impl From<usize> for VarInt {
fn from(value: usize) -> Self {
VarInt(value as i32)
}
}

impl From<VarInt> for i32 {
fn from(value: VarInt) -> Self {
value.0
}
}

impl AsRef<i32> for VarInt {
fn as_ref(&self) -> &i32 {
&self.0
}
}

impl Deref for VarInt {
type Target = i32;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Serialize for VarInt {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut value = self.0 as u32;
let mut buf = Vec::new();

while value > 0x7F {
buf.put_u8(value as u8 | 0x80);
value >>= 7;
}

buf.put_u8(value as u8);

serializer.serialize_bytes(&buf)
}
}

impl<'de> Deserialize<'de> for VarInt {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct VarIntVisitor;

impl<'de> Visitor<'de> for VarIntVisitor {
type Value = VarInt;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid VarInt encoded in a byte sequence")
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut val = 0;
for i in 0..VarInt::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? {
val |= (i32::from(byte) & 0b01111111) << (i * 7);
if byte & 0b10000000 == 0 {
return Ok(VarInt(val));
}
} else {
break;
}
}
Err(serde::de::Error::custom("VarInt was too large"))
}
}

deserializer.deserialize_seq(VarIntVisitor)
}
}
Loading

0 comments on commit fd66790

Please sign in to comment.