mclib 0.0.1

Utils and helpers for Minecraft protocol
Documentation
use crate::types::base::MCType;
use crate::utils::TcpUtils;
use std::io::Read;

const SEGMENT_BITS: u8 = 0b0111_1111;
const CONTINUE_BIT: u8 = 0b1000_0000;

#[derive(Debug, Clone)]
pub struct MCVarInt(i32);

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

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

impl PartialEq<i32> for MCVarInt {
    fn eq(&self, other: &i32) -> bool {
        &self.0 == other
    }
}

impl MCType for MCVarInt {
    fn pack(&self) -> Vec<u8> {
        let mut value = self.0;
        let mut result = Vec::new();

        for _ in 0..100 {
            if (value & !(SEGMENT_BITS as i32)) == 0 {
                result.push(value as u8);
                break;
            }

            result.push(((value as u8) & SEGMENT_BITS) | CONTINUE_BIT);

            value >>= 7;
            value &= i32::MAX >> 6;
        }

        result
    }

    fn unpack(src: &mut dyn Read) -> Self {
        let mut value = 0i32;

        for i in 0..5 {
            let current_byte = src.read_byte();
            value |= ((current_byte & SEGMENT_BITS) as i32) << (i * 7);

            if (current_byte & CONTINUE_BIT) == 0 {
                break;
            }
        }

        Self(value)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_varint_pack() {
        assert_eq!(vec![0x00], MCVarInt::from(0).pack());
        assert_eq!(vec![0x01], MCVarInt::from(1).pack());
        assert_eq!(vec![0x02], MCVarInt::from(2).pack());
        assert_eq!(vec![0x7f], MCVarInt::from(127).pack());
        assert_eq!(vec![0x80, 0x01], MCVarInt::from(128).pack());
        assert_eq!(vec![0xff, 0x01], MCVarInt::from(255).pack());
        assert_eq!(vec![0xdd, 0xc7, 0x01], MCVarInt::from(25565).pack());
        assert_eq!(vec![0xff, 0xff, 0x7f], MCVarInt::from(2097151).pack());
        assert_eq!(
            vec![0xff, 0xff, 0xff, 0xff, 0x07],
            MCVarInt::from(2147483647).pack()
        );
        assert_eq!(
            vec![0xff, 0xff, 0xff, 0xff, 0x0f],
            MCVarInt::from(-1).pack()
        );
        assert_eq!(
            vec![0x80, 0x80, 0x80, 0x80, 0x08],
            MCVarInt::from(-2147483648).pack()
        );
    }

    #[test]
    fn test_varint_unpack() {
        assert_eq!(MCVarInt::unpack(&mut std::io::Cursor::new(vec![0x00])), 0);
        assert_eq!(MCVarInt::unpack(&mut std::io::Cursor::new(vec![0x01])), 1);
        assert_eq!(MCVarInt::unpack(&mut std::io::Cursor::new(vec![0x02])), 2);
        assert_eq!(MCVarInt::unpack(&mut std::io::Cursor::new(vec![0x7f])), 127);
        assert_eq!(
            MCVarInt::unpack(&mut std::io::Cursor::new(vec![0x80, 0x01])),
            128
        );
        assert_eq!(
            MCVarInt::unpack(&mut std::io::Cursor::new(vec![0xff, 0x01])),
            255
        );
        assert_eq!(
            MCVarInt::unpack(&mut std::io::Cursor::new(vec![0xdd, 0xc7, 0x01])),
            25565
        );
        assert_eq!(
            MCVarInt::unpack(&mut std::io::Cursor::new(vec![0xff, 0xff, 0x7f])),
            2097151
        );
        assert_eq!(
            MCVarInt::unpack(&mut std::io::Cursor::new(vec![
                0xff, 0xff, 0xff, 0xff, 0x07
            ])),
            2147483647
        );
        assert_eq!(
            MCVarInt::unpack(&mut std::io::Cursor::new(vec![
                0xff, 0xff, 0xff, 0xff, 0x0f
            ])),
            -1
        );
        assert_eq!(
            MCVarInt::unpack(&mut std::io::Cursor::new(vec![
                0x80, 0x80, 0x80, 0x80, 0x08
            ])),
            -2147483648
        );
    }
}