composition/src/mctypes/numbers.rs
2022-04-16 13:18:49 -06:00

188 lines
4.9 KiB
Rust

use crate::prelude::*;
pub fn parse_byte(data: &[u8]) -> ParseResult<i8> {
if data.is_empty() {
Err(ParseError::NotEnoughData)
} else {
let value = i8::from_be_bytes([data[0]]);
Ok((value, 1))
}
}
pub fn serialize_byte(num: i8) -> [u8; 1] {
num.to_be_bytes()
}
pub fn parse_short(data: &[u8]) -> ParseResult<i16> {
if data.len() < 2 {
Err(ParseError::NotEnoughData)
} else {
let value = i16::from_be_bytes([data[0], data[1]]);
Ok((value, 2))
}
}
pub fn serialize_short(num: i16) -> [u8; 2] {
num.to_be_bytes()
}
pub fn parse_int(data: &[u8]) -> ParseResult<i32> {
if data.len() < 4 {
Err(ParseError::NotEnoughData)
} else {
let value = i32::from_be_bytes([data[0], data[1], data[2], data[3]]);
Ok((value, 4))
}
}
pub fn serialize_int(num: i32) -> [u8; 4] {
num.to_be_bytes()
}
pub fn parse_long(data: &[u8]) -> ParseResult<i64> {
if data.len() < 8 {
Err(ParseError::NotEnoughData)
} else {
let value = i64::from_be_bytes([
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
]);
Ok((value, 8))
}
}
pub fn serialize_long(num: i64) -> [u8; 8] {
num.to_be_bytes()
}
pub fn parse_varint(data: &[u8]) -> ParseResult<i32> {
let mut offset = 0;
let mut output = 0i32;
let mut bytes_read = 0i32;
loop {
if data.len() <= offset {
return Err(ParseError::NotEnoughData);
}
output |= (((data[offset] & 0x7f) as i32) << bytes_read * 7) as i32;
bytes_read += 1;
if data[offset] & 0x80 != 0x80 {
break;
}
offset += 1;
if bytes_read >= 5 {
return Err(ParseError::VarIntTooBig);
}
}
Ok((output, bytes_read as usize))
}
pub fn serialize_varint(value: i32) -> Vec<u8> {
println!("serializing {}", value);
let mut value = value as u32;
let mut output = vec![];
loop {
let data = (value & 0x7f) as u8;
value >>= 7;
println!("\tvalue: {}", value);
if value == 0 {
output.push(data);
break;
} else {
output.push(data | 0x80);
}
}
output
}
pub fn parse_unsigned_byte(data: &[u8]) -> ParseResult<u8> {
if data.is_empty() {
Err(ParseError::NotEnoughData)
} else {
let value = u8::from_be_bytes([data[0]]);
Ok((value, 1))
}
}
pub fn serialize_unsigned_byte(num: u8) -> [u8; 1] {
num.to_be_bytes()
}
pub fn parse_unsigned_short(data: &[u8]) -> ParseResult<u16> {
if data.len() < 2 {
Err(ParseError::NotEnoughData)
} else {
let value = u16::from_be_bytes([data[0], data[1]]);
Ok((value, 2))
}
}
pub fn serialize_unsigned_short(num: u16) -> [u8; 2] {
num.to_be_bytes()
}
pub fn parse_unsigned_int(data: &[u8]) -> ParseResult<u32> {
if data.len() < 4 {
Err(ParseError::NotEnoughData)
} else {
let value = u32::from_be_bytes([data[0], data[1], data[2], data[3]]);
Ok((value, 4))
}
}
pub fn serialize_unsigned_int(num: u32) -> [u8; 4] {
num.to_be_bytes()
}
pub fn parse_unsigned_long(data: &[u8]) -> ParseResult<u64> {
if data.len() < 8 {
Err(ParseError::NotEnoughData)
} else {
let value = u64::from_be_bytes([
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
]);
Ok((value, 8))
}
}
pub fn serialize_unsigned_long(num: u64) -> [u8; 8] {
num.to_be_bytes()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_varint_works() {
let tests = vec![
(Ok((0, 1)), vec![0x00]),
(Ok((1, 1)), vec![0x01]),
(Ok((2, 1)), vec![0x02]),
(Ok((127, 1)), vec![0x7f]),
(Ok((128, 2)), vec![0x80, 0x01]),
(Ok((255, 2)), vec![0xff, 0x01]),
(Ok((25565, 3)), vec![0xdd, 0xc7, 0x01]),
(Ok((2097151, 3)), vec![0xff, 0xff, 0x7f]),
(Ok((2147483647, 5)), vec![0xff, 0xff, 0xff, 0xff, 0x07]),
(Ok((-1, 5)), vec![0xff, 0xff, 0xff, 0xff, 0x0f]),
(Ok((-2147483648, 5)), vec![0x80, 0x80, 0x80, 0x80, 0x08]),
];
for test in &tests {
assert_eq!(test.0, parse_varint(&test.1));
}
}
#[test]
fn serialize_varint_works() {
let tests = vec![
(0, vec![0x00]),
(1, vec![0x01]),
(2, vec![0x02]),
(127, vec![0x7f]),
(128, vec![0x80, 0x01]),
(255, vec![0xff, 0x01]),
(25565, vec![0xdd, 0xc7, 0x01]),
(2097151, vec![0xff, 0xff, 0x7f]),
(2147483647, vec![0xff, 0xff, 0xff, 0xff, 0x07]),
(-1, vec![0xff, 0xff, 0xff, 0xff, 0x0f]),
(-2147483648, vec![0x80, 0x80, 0x80, 0x80, 0x08]),
];
for test in &tests {
assert_eq!(serialize_varint(test.0), test.1);
}
}
}